原题传送门
相关题意请了解后再来看此篇题解 (绝不是偷懒
正篇
题目让我们求的是
∑
i
=
1
n
∑
j
=
1
n
∑
k
=
1
n
(
x
i
&
x
j
)
⋅
(
x
j
∣
x
k
)
\displaystyle \sum_{i=1}^n \sum_{j=1}^n \sum_{k=1}^n (x_i \, \& \, x_j) \cdot (x_j \, | \, x_k)
i=1∑nj=1∑nk=1∑n(xi&xj)⋅(xj∣xk)。这个式子看起来比较复杂,有三个变量,但是不难发现,这里变量
i
\displaystyle i
i和变量
j
\displaystyle j
j绑定,而变量
j
\displaystyle j
j又与变量
k
\displaystyle k
k绑定,且题目数据范围非常大,我们不太可能枚举两个这样的大范围变量,故考虑对和式化简,以便我们处理。注意到对每一个给定的
j
\displaystyle j
j有
n
\displaystyle n
n个值要跟它取或运算并求和,于是我们将和式进行第一步转化得到如下式子:
∑
i
=
1
n
∑
j
=
1
n
(
x
i
&
x
j
)
∑
k
=
1
n
(
x
j
∣
x
k
)
\displaystyle \sum_{i=1}^n \sum_{j=1}^n(x_i \, \& \, x_j) \sum_{k=1}^n (x_j \, | \, x_k)
i=1∑nj=1∑n(xi&xj)k=1∑n(xj∣xk)
但是光化简这一步,我们的和式依旧很难处理,这里的求和顺序是先给定一个
i
\displaystyle i
i,然后枚举
j
\displaystyle j
j在对每一个给定的
j
\displaystyle j
j对
k
\displaystyle k
k进行求和,形成了一个类似链一样的传递,我们不妨在思考一下,前面的两个和式意义是什么?其实就是枚举了
(
i
,
j
)
\displaystyle (i,j)
(i,j)对,那么我们是否可以考虑将
j
\displaystyle j
j转化为"最高优先级",对于每一个
i
\displaystyle i
i有
n
\displaystyle n
n个
j
\displaystyle j
j可以与其配对,那么反过来,对于每一个
j
\displaystyle j
j同样有
n
\displaystyle n
n个
i
\displaystyle i
i与其配对。于是和式又可以进一步转化:
∑
j
=
1
n
(
∑
i
=
1
n
(
x
i
&
x
j
)
∑
k
=
1
n
(
x
j
∣
x
k
)
)
\displaystyle\sum_{j=1}^n (\sum_{i=1}^n (x_i \, \& \, x_j) \sum_{k=1}^n (x_j \, | \, x_k))
j=1∑n(i=1∑n(xi&xj)k=1∑n(xj∣xk))
对于这个式子,我们就相对好处理很多了,我们只需要能够快速求得
x
j
\displaystyle x_j
xj与整个序列的"&“运算和,以及
x
j
\displaystyle x_j
xj与整个序列的”|“运算和。由于都是位运算,整体考虑,肯定是很困难的,我们不妨把每一位拿出来考虑,毕竟最多也只有60位,枚举一下还是可以接受的。
我们单独思考每一位,一个数的二进制表示的某一位无非两种情况,要么是0,要么就是1。这样我们进行分类:
(
1
)
\displaystyle (1)
(1)如果
x
j
\displaystyle x_j
xj的第
p
\displaystyle p
p位是0,那么这一位的”&“运算一定是0,对答案无贡献,再考虑”|“运算,由于这一位是1,那么它或上任意值都是那个数本身,那么这一位的贡献便是所有数在这一位的贡献。即:
∑
i
=
1
n
(
x
i
p
&
x
j
p
)
=
0
\displaystyle\sum_{i=1}^n (x_{ip}\, \& \, x_{jp})=0
i=1∑n(xip&xjp)=0
∑
k
=
1
n
(
x
j
p
∣
x
k
p
)
=
∑
i
=
1
n
x
i
p
\displaystyle\sum_{k=1}^n (x_{jp} \, | \, x_{kp})=\sum_{i=1}^n x_{ip}
k=1∑n(xjp∣xkp)=i=1∑nxip
(
2
)
\displaystyle (2)
(2)如果
x
j
\displaystyle x_j
xj的第
p
\displaystyle p
p位是1,那么这一位的”&“运算和便是所有数在这一位的贡献,在考虑”|"运算,由于1或上任意数都是1,所以这一位将贡献n个1。即:
∑
i
=
1
n
(
x
i
p
&
x
j
p
)
=
∑
i
=
1
n
x
i
p
\displaystyle\sum_{i=1}^n (x_{ip}\, \& \, x_{jp})=\sum_{i=1}^n x_{ip}
i=1∑n(xip&xjp)=i=1∑nxip
∑
k
=
1
n
(
x
j
p
∣
x
k
p
)
=
n
\displaystyle\sum_{k=1}^n (x_{jp} \, | \, x_{kp})=n
k=1∑n(xjp∣xkp)=n
注意上述求和的结果是1的个数。
那么这篇题解就到此为止了,以下是我丑陋的代码:
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
using namespace std;
#define ACCPECT return 0;
const int p = 1e9+7;
const int N = 5e5+10;
typedef long long ll;
typedef pair<ll,ll> PII;
int t;
ll n;
ll x[N];
ll cnt[61];
void solve(){
scanf("%lld",&n);
for(int i = 1; i <= 60; ++i) cnt[i] = 0;
for(int i = 1; i <= n ; ++i)scanf("%lld",&x[i]);
for(int j = 1; j <= n; ++j){//预处理每一位1的个数
for(int i = 0; i < 60; ++i){
if((x[j] >> (i*1ll)) & 1)++cnt[i+1];
}
}
ll ans = 0;
ll sum_and = 0, sum_or = 0;
for(int i = 1; i <= n; ++i){
sum_and = 0, sum_or = 0;
for(int j = 0; j < 60; ++j){
if((x[i] >> (j*1ll)) & 1){
sum_and = sum_and + ((1ll << j)%p) * cnt[j+1] % p;
sum_and %=p;
//cout<<j<<":::"<<sum_and<<'\n';
sum_or = sum_or + ((1ll << j)%p) * n % p;
sum_or %= p;
//cout<<j<<":::"<<sum_or<<'\n';
} else {
sum_or += ((1ll << j)%p) * cnt[j+1] % p;
sum_or %= p;
}
}
ans = (ans + (sum_and * sum_or) % p) % p;
}
cout<<ans<<'\n';
}
signed main(){
#ifdef ACM_LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
t = 1;
scanf("%d",&t);
while(t--){
solve();
}
fclose(stdin);
fclose(stdout);
//--------
ACCPECT;
//--------
}