位运算
添加链接描述
思路
按位统计,计算每位的贡献。先算出每位为
1
1
1的个数
c
n
t
[
i
]
cnt[i]
cnt[i],然后
n
−
c
n
t
[
i
]
n-cnt[i]
n−cnt[i]就是每位为
0
0
0的个数。当每次取
3
3
3个数,对应的位做异或运算时,只有当运算结果为
1
1
1,那一位才会对结果有贡献。由于只有
1
x
o
r
1
x
o
r
1
1 xor 1 xor 1
1xor1xor1和
1
x
o
r
0
x
o
r
0
1xor0xor0
1xor0xor0运算结果才为
1
1
1,所以对每一位,1的个数里面取
3
3
3个
1
1
1,或者
1
1
1的个数里面取
1
1
1个
1
1
1,两个
0
0
0。加起来,再乘
2
i
2^i
2i即可。
补充取模运算运算规则
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p) % p
(a * b) % p = (a % p * b % p) % p
a ^ b % p = ((a % p)^b) % p
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e6+5;
const ll mod = 1e9+7;
ll n, cnt[N], ans;
ll c_2(ll n)
{
return n*(n-1)/2;
}
ll c_3(ll n)
{
return n*(n-1)*(n-2)/6;
}
int main()
{
cin >> n;
for(ll i=0; i<n; i++)
{
ll x, m = 0;
cin >> x;
while(x)
{
if(x & 1)
cnt[m]++;
x >>= 1;
m++;
}
}
ll res = 1;
for (int i = 0; i < 64; i++)
{
ans = (ans + (c_3(cnt[i]) + cnt[i] * c_2(n - cnt[i])) % mod * res) % mod;
res = (res << 1) % mod;
}
cout << ans << endl;
return 0;
}