题目大意
给定nnn个整数a1,a2,…,ana_1,a_2,\dots,a_na1,a2,…,an,求
∑i=1n∑j=in(⨁k=ijak)2\sum\limits_{i=1}^n\sum\limits_{j=i}^n(\bigoplus\limits _{k=i}^ja_k)^2i=1∑nj=i∑n(k=i⨁jak)2
输出答案模998244353998244353998244353后的值。
注: ⨁k=ijak=ai⊕ai+1⊕⋯⊕aj\bigoplus\limits _{k=i}^ja_k=a_i\oplus a_{i+1}\oplus \cdots \oplus a_jk=i⨁jak=ai⊕ai+1⊕⋯⊕aj
1≤n≤2×105,1≤ai≤2×1051\leq n\leq 2\times 10^5,1\leq a_i\leq 2\times 10^51≤n≤2×105,1≤ai≤2×105
题解
令di=⨁j=1iajd_i=\bigoplus\limits _{j=1}^ia_jdi=j=1⨁iaj,则原式变为
∑i=1n∑j=in(dj⊕di−1)2\sum\limits_{i=1}^n\sum\limits_{j=i}^n(d_j\oplus d_{i-1})^2i=1∑nj=i∑n(dj⊕di−1)2
我们按位来考虑,枚举每一位kkk,那么原式变为
∑k=0mx2k∑(dj⊕di−1)&2k=2k(dj⊕di−1)\sum\limits_{k=0}^{mx}2^k\sum\limits_{(d_j\oplus d_{i-1})\& 2^k=2^k}(d_j\oplus d_{i-1})k=0∑mx2k(dj⊕di−1)&2k=2k∑(dj⊕di−1)
其中mxmxmx表示所有did_idi的二进制最高位的是从低到高的第几位。
我们可以用vectorvectorvector来存每一位为000或为111的数。也就是说,对于每个数did_idi,枚举它的每一位kkk,如果这一位为000,则将did_idi放在vk,0v_{k,0}vk,0中;如果这一位为111,则将did_idi放在vk,1v_{k,1}vk,1中。这里的vk,0/1v_{k,0/1}vk,0/1是vectorvectorvector类型的。
然后,枚举每一个kkk,我们要求的就是∑(dj⊕di−1)&2k=2k(dj⊕di−1)\sum\limits_{(d_j\oplus d_{i-1})\& 2^k=2^k}(d_j\oplus d_{i-1})(dj⊕di−1)&2k=2k∑(dj⊕di−1)。既然要异或后的第kkk位为111,那么djd_jdj和di−1d_{i-1}di−1的第kkk位肯定不同。那么,我们需要求vk,0v_{k,0}vk,0和vk,1v_{k,1}vk,1中各取一个数来异或,然后将所有情况求和。
这怎么处理呢?我们还是按每一位来计算。枚举每一位ttt,如果异或和的第ttt位为111,则在vk,0v_{k,0}vk,0中选的数和vk,1v_{k,1}vk,1中选的数的第ttt位肯定不同。那么,我们记录vk,0v_{k,0}vk,0中的每一位ttt有多少个数为000,多少个数为111,记为hvt,0/1hv_{t,0/1}hvt,0/1,那么对于vk,1v_{k,1}vk,1中的每一位ttt,设这一位为vvv(vvv的值为000或111),其贡献为2t×hvt,1−v2^t\times hv_{t,1-v}2t×hvt,1−v。
注意d0d_0d0也要加入vectorvectorvector。因为这是vk,0v_{k,0}vk,0中的数异或vk,1v_{k,1}vk,1中的数,所以是有序的,不需要除以222。
时间复杂度为O(nlog2n)O(n\log^2 n)O(nlog2n)。
code
#include<bits/stdc++.h>
using namespace std;
const int N=200000;
const long long mod=998244353;
int n,a[N+5],b[N+5],hv[25][2];
long long ans=0;
vector<int>v[25][2];
int main()
{
// freopen("origen.in","r",stdin);
// freopen("origen.out","w",stdout);
scanf("%d",&n);
for(int j=0;j<=19;j++){
v[j][0].push_back(0);
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=b[i-1]^a[i];
for(int j=0;j<=19;j++){
v[j][(b[i]>>j)&1].push_back(b[i]);
}
}
for(int i=0;i<=19;i++){
for(int j=0;j<=19;j++) hv[j][0]=hv[j][1]=0;
for(int j=0;j<v[i][0].size();j++){
int t=v[i][0][j];
for(int k=0;k<=19;k++){
++hv[k][(t>>k)&1];
}
}
long long tmp=0;
for(int j=0;j<v[i][1].size();j++){
int t=v[i][1][j];
for(int k=0;k<=19;k++){
int vk=((t>>k)&1)^1;
tmp=(tmp+1ll*hv[k][vk]*(1<<k))%mod;
}
}
ans=(ans+tmp*(1<<i))%mod;
}
printf("%lld",ans);
return 0;
}
文章讲述了如何解决一个关于整数序列中异或操作后平方和的问题,通过位运算和向量存储优化,降低了时间复杂度至O(nlog^2n)。
1438

被折叠的 条评论
为什么被折叠?



