题目描述
Only a few know that Pan and Apollo weren’t only battling for the title of the GOAT musician. A few millenniums later, they also challenged each other in math (or rather in fast calculations). The task they got to solve is the following:
Let x1,x2,…,xn be the sequence of n non-negative integers. Find this value:
∑i=1n∑j=1n∑k=1n(xi&xj)⋅(xj|xk)
Here & denotes the bitwise and, and | denotes the bitwise or.
Pan and Apollo could solve this in a few seconds. Can you do it too? For convenience, find the answer modulo 109+7.
Input
The first line of the input contains a single integer t (1≤t≤1000) denoting the number of test cases, then t test cases follow.
The first line of each test case consists of a single integer n (1≤n≤5⋅105), the length of the sequence. The second one contains n non-negative integers x1,x2,…,xn (0≤xi<260), elements of the sequence.
The sum of n over all test cases will not exceed 5⋅105.
Output
Print t lines. The i-th line should contain the answer to the i-th text case.
Example
input
8
2
1 7
3
1 2 4
4
5 5 5 5
5
6 2 2 1 0
1
0
1
1
6
1 12 123 1234 12345 123456
5
536870912 536870911 1152921504606846975 1152921504606846974 1152921504606846973
output
128
91
1600
505
0
1
502811676
264880351
题目大意
计算公式: ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n ( a [ i ] \displaystyle\sum_{i=1}^{n}\displaystyle\sum_{j=1}^{n}\displaystyle\sum_{k=1}^{n}(a[i] i=1∑nj=1∑nk=1∑n(a[i]& a [ j ] ) ∗ ( a [ j ] ∣ a [ k ] ) a[j])*(a[j]|a[k]) a[j])∗(a[j]∣a[k])的值。
题目分析
在这个题中,我们要做的就是将O(n3)的公式优化到O(n)。
先来看看如何优化到O(n2):
原 式 原式 原式
= ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n ( a [ i ] \displaystyle\sum_{i=1}^{n}\displaystyle\sum_{j=1}^{n}\displaystyle\sum_{k=1}^{n}(a[i] i=1∑nj=1∑nk=1∑n(a[i]& a [ j ] ) ∗ ( a [ j ] ∣ a [ k ] ) a[j])*(a[j]|a[k]) a[j])∗(a[j]∣a[k])
= ∑ j = 1 n ∑ i = 1 n ∑ k = 1 n ( a [ i ] \displaystyle\sum_{j=1}^{n}\displaystyle\sum_{i=1}^{n}\displaystyle\sum_{k=1}^{n}(a[i] j=1∑ni=1∑nk=1∑n(a[i]& a [ j ] ) ∗ ( a [ j ] ∣ a [ k ] ) a[j])*(a[j]|a[k]) a[j])∗(a[j]∣a[k])
= ∑ j = 1 n ( ∑ i = 1 n a [ i ] \displaystyle\sum_{j=1}^{n}(\displaystyle\sum_{i=1}^{n}a[i] j=1∑n(i=1∑na[i]& a [ j ] ) ∗ ( ∑ k = 1 n a [ j ] ∣ a [ k ] ) a[j])*(\displaystyle\sum_{k=1}^{n}a[j]|a[k]) a[j])∗(k=1∑na[j]∣a[k])
经过了一系列的变形,我们就可以将其优化到O(n2)了。
要再将其优化到O(n)就需要运用位运算的性质了:
- 首先我们可以统计一下这n个数的二进制形式中,都是那些位上是1(这一步可以预处理出来)
cnt[i] //表示这n个数中有多少个数的二进制在第i位上是1
。 - 枚举这n个数(j的那一层循环),再枚举二进制的每一位数(本题中一共是60位,用i表示)。
- 如果a[j]在第i位上是1,那么&的这一部分的值为 c n t [ i ] ∗ ( 1 < < i ) cnt[i]*(1<<i) cnt[i]∗(1<<i),而 | 的这一部分的值为 n ∗ ( 1 < < i ) n*(1<<i) n∗(1<<i)。
- 如果a[j]在第i位上是0,那么&的这一部分的值为0,而 | 的这一部分的值为 c n t [ i ] ∗ ( 1 < < i ) cnt[i]*(1<<i) cnt[i]∗(1<<i)。
- 算出所有位置上&和 | 的和之后相乘,即可得到 ( ∑ i = 1 n a [ i ] (\displaystyle\sum_{i=1}^{n}a[i] (i=1∑na[i]& a [ j ] ) ∗ ( ∑ k = 1 n a [ j ] ∣ a [ k ] ) a[j])*(\displaystyle\sum_{k=1}^{n}a[j]|a[k]) a[j])∗(k=1∑na[j]∣a[k]) 的值。这样就能将O(n)的时间复杂度优化到O(60)。最终的时间复杂度即为O(60*n)。
代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <unordered_map>
#include <queue>
#include <vector>
#include <set>
#include <bitset>
#include <algorithm>
#define LL long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=5e5+5,mod=1e9+7;
LL a[N],p[65];
int cnt[65];
int main()
{
for(int i=0;i<61;i++) i?p[i]=p[i-1]*2%mod:p[0]=1; //先预处理出2^i的值
int t;
scanf("%d",&t);
while(t--)
{
memset(cnt,0,sizeof cnt);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=0;i<61;i++) //预处理出这n个数中有多少个在第i位上的值是1
for(int j=1;j<=n;j++)
if((a[j]>>i)&1) cnt[i]++;
LL ans=0;
for(int j=1;j<=n;j++) //枚举j层
{
LL t1=0,t2=0; //t1记录&部分的和,t2记录|部分的和
for(int i=0;i<61;i++) //枚举二进制的60位
{
if((a[j]>>i)&1) //a[j]在第i位上是1的情况
{
t1=(t1+cnt[i]*p[i])%mod;
t2=(t2+n*p[i])%mod;
}
else t2=(t2+cnt[i]*p[i])%mod; //a[j]在第i位上是0的情况
}
ans=(ans+t1*t2)%mod;
}
printf("%lld\n",ans);
}
return 0;
}