E. Apollo versus Pan
题意:
给定一个长度为
n
n
n 的序列,然后对下列式子求和,答案对
1
0
9
+
7
10^9+7
109+7 取模
∑
i
=
1
n
∑
j
=
1
n
∑
k
=
1
n
(
x
i
&
x
j
)
∗
(
x
j
∣
x
k
)
\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n(x_i\&x_j)*(x_j|x_k)
i=1∑nj=1∑nk=1∑n(xi&xj)∗(xj∣xk)
思路:
题解
先交换求和号顺序
∑
j
=
1
n
∑
i
=
1
n
∑
k
=
1
n
(
x
i
&
x
j
)
∗
(
x
j
∣
x
k
)
\sum_{j=1}^n\sum_{i=1}^n\sum_{k=1}^n(x_i\&x_j)*(x_j|x_k)\\
j=1∑ni=1∑nk=1∑n(xi&xj)∗(xj∣xk)
提出公因式,对于最后一个项来说,
i
i
i 和
j
j
j 都是固定的,可以看成常数提出来
∑
j
=
1
n
∑
i
=
1
n
(
(
x
i
&
x
j
)
∗
∑
k
=
1
n
(
x
j
∣
x
k
)
)
\sum_{j=1}^n\sum_{i=1}^n\Bigg( (x_i\&x_j)*\sum_{k=1}^n(x_j|x_k)\Bigg)\\
j=1∑ni=1∑n((xi&xj)∗k=1∑n(xj∣xk))
对于第二项的每一项,
j
j
j 是固定的,
k
k
k 每次都是从
1
1
1 到
k
k
k,也是固定的,所以可以提出来第三项,然后变成两项的乘积
∑
j
=
1
n
(
∑
i
=
1
n
(
x
i
&
x
j
)
)
∗
(
∑
k
=
1
n
(
x
j
∣
x
k
)
)
\sum_{j=1}^n\Bigg(\sum_{i=1}^n(x_i\&x_j)\Bigg)*\Bigg( \sum_{k=1}^n(x_j|x_k) \Bigg)
j=1∑n(i=1∑n(xi&xj))∗(k=1∑n(xj∣xk))
然后拆位预处理,每次计算每一位的贡献就好了
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
ll d[maxn];
void work()
{
ll cnt[70] = {0};
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> d[i];
for(int j = 0; j < 60; ++j) if(d[i] & (1ll << j))
++cnt[j];
}
ll ans = 0;
for(int i = 1; i <= n; ++i){
ll a = 0, b = 0;
for(int j = 0; j < 60; ++j){
ll x = (1ll << j) % mod;
if(d[i] & (1ll << j))
(a += cnt[j] * x % mod) %= mod, (b += n * x % mod) %= mod;
else
(b += cnt[j] * x % mod) %= mod;
}
(ans += a * b % mod) %= mod;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(0);
int TT;cin>>TT;while(TT--)
work();
return 0;
}