题意:
给一个长度为 n(n <= 5e5) 的数组 求 :
思路:
写了几项 发现这个式子可以变成 (x1 & x1 + x1 & x2 + x1 & x3 + …) * (x1 | x1 + x1 | x2 + x1 | x3 + …)+ (x2 & x1 + x2 & x2 + x2 & x3 + …) * (x2 | x1 + x2 | x2 + x2 | x3 + …) + …也就是 n 项和的形式。所以我们只需要快速算出 每一项的值,这里我们可以按位算贡献 可以做到 o(60) 的复杂度 ,最后的复杂度就是 o(n * 60),考虑每一个二进制位,统计每一位 1 的个数,根据位运算的性质就可以求出答案(具体看代码)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 7;
int n,m;
int T;
ll poww[maxn],a[maxn],cnt[100];
ll ans;
int main(){
scanf("%d",&T);
poww[0] = 1;
for(int i = 1; i <= 1e6; i ++){
poww[i] = poww[i - 1] * 2 % mod;
}
while(T--){
scanf("%d",&n);
memset(cnt,0,sizeof(cnt));
ans = 0;
for(int i = 1; i <= n; i ++){
scanf("%lld",&a[i]);
}
for(int i = 0; i <= 60; i ++){
for(int j = 1; j <= n; j ++){
if((a[j] >> i) & 1) cnt[i]++;
}
}
for(int i = 1; i <= n; i ++){
ll sum1 = 0,sum2 = 0;
for(int j = 0; j <= 60; j ++){
if((a[i] >> j) & 1){
sum1 = (sum1 + cnt[j] * poww[j]) % mod;
sum2 = (sum2 + n * poww[j]) % mod;
}
else sum2 = (sum2 + cnt[j] * poww[j]) % mod;
}
ans = (ans + sum1 * sum2 % mod) % mod;
}
printf ("%lld\n",ans);
}
return 0;
}