题目大意::给定长度为的数列,定义,求下式:
解题思路:可以逐位考虑,分别计算贡献。
首先可以考虑计算
设表示第i个数对答案的贡献,为序列的异或前缀和,由异或的性质可知若二进制下第位为,则需要寻找,才会对答案有贡献,显然这是可以预处理的。
:
链接
参考代码:
#define LL long long
using namespace std;
const int M=1e5+7;
const LL Mod=998244353;
int n;
LL anq=0;
LL a[M],s[M],pre[M],P[3];
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
pre[0]=0;
pre[1]=a[1];
for(int i=2;i<=n;i++){
pre[i]=pre[i-1]^a[i];
}
for(int bit=0;bit<=20;bit++){
P[0]=1;P[1]=0;
for(int i=1;i<=n;i++){
if((pre[i]>>bit)&1){
s[i]=P[0]; P[1]++;
} else {
s[i]=P[1]; P[0]++;
}
anq=anq+s[i]*(1<<bit);
}
}
cout<<anq<<"\n";
}
接下来,可以考虑求
首先还是考虑拆位。设,考虑当固定时,可以枚举,如果此区间在此位上异或值为,那么对答案贡献便为,即第一区间的右端点在上。因而可以考虑随着增
大维护数组表示该位上前缀异或和为或的的贡献和。
此题k=3,同理可推
注意到
参考代码:
#define LL long long
using namespace std;
const int M=2e5+7;
const LL Mod=998244353;
int n;
LL anq=0;
LL a[M],s[M],pre[M],P[3],ss[M];
int main(){
ios::sync_with_stdio(false);
cin>>n;
s[0]=1;
for(int i=1;i<=n;i++){
cin>>a[i];
pre[i]=pre[i-1]^a[i];
s[i]=1;
}
for(int k=1;k<=3;k++){
for(int bit=0;bit<=30;bit++){
P[0]=P[1]=0;
if(k==1) P[0]=1; //P[x=0/1] 表示之前在 x 前放 k-1 个不相交的区间,所有方案下这些区间的权值和
for(int i=1;i<=n;i++){
ss[i]=(ss[i]+(P[((pre[i]>>bit)&1)^1]<<bit))%Mod;
P[(pre[i]>>bit)&1]=(1ll*P[(pre[i]>>bit)&1]+s[i])%Mod;
//cout<<k<<" "<<bit<<" "<<i<<":"<<P[0]<<" "<<P[1]<<" "<<ss[i]<<"\n";
}
}
s[0]=0;
for(int i=1;i<=n;i++){
s[i]=(s[i-1]+ss[i])%Mod;
ss[i]=0;
}
}
cout<<s[n]<<"\n";
}