ABC365E 题解
考虑拆位计算,算每一位的答案。
那原题就转化成在 序列上的求值。
对于快速求一段区间的异或和,显然想到先对每一位做个前缀异或和。
举样例 的第三位为例子:
做完前缀异或和后变为:
显然异或和为 是不会对答案有贡献。因为这是个 序列,所以对于每一个数,对答案的贡献是这个数之前与其值不同的个数。
例如:第 个数,它前面有 个与其不同(第 和第 个),所以贡献是 (区间是 )。
然后就可以算了。
#include<bits/stdc++.h>
using namespace std;
inline void ri(int &_a){
int res=0,f=1;
char c;
for(;(c=getchar())<'0'||c>'9';c=='-'?f=-f:0);
while(c>='0' && c<='9') res=(res<<1) + (res<<3) + c-'0',c=getchar();
_a=res*f;
}
inline void rll(long long &_a){
long long res=0ll,f=1;
char c;
for(;(c=getchar())<'0'||c>'9';c=='-'?f=-f:0);
while(c>='0' && c<='9') res=(res<<1) + (res<<3) + c-'0',c=getchar();
_a=res*f;
}
/*-----------------*/
int n;
long long a[200010],ans;
int main(){
ri(n);
for(int i=1;i<=n;i++) rll(a[i]);
for(int i=0;i<40;i++){
int p=0,q=0,now=0;
long long sum=0;
for(int j=1;j<=n;j++){
int up=now;
now^=(a[j]&1);
sum+=(now?p:q);
a[j]>>=1;
up?q++:p++;
}
ans+=1ll*sum*(1ll<<i);
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号