Skip to content

异或

P3760

对于连续区间,可以想到用前缀和\(s[j]-s[i-1]\)表示\(\sum_{k=i}^{j}a[k]\)

那么,对于答案每一位\(k\),求出有多少\(s[j]-s[i]\)\(k\)位为1。

那么,从头到尾扫描\(s[j]\),用权值树状数组(两个,一个维护第k位是0,一个维护第k位是1)维护之前的\(s[i]\),对这一位的答案有贡献的只有那些第k位为1且第k位向右的数比s[i]第k位向右的数大的或者第k位为0且第k位向右的数不比s[i]第k位向右的数大的。

#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long 
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e5+10,C=1e6+10;
int s[N],a[N],f[C][2];
int n,maxn,ans;
void change(int i,int x,int d){
    while(x<C)f[x][i]+=d,x+=lowbit(x);
}
int sum(int i,int x){
    int ans=0;
    while(x>0)ans+=f[x][i],x-=lowbit(x);
    return ans;
}
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]),s[i]=s[i-1]+a[i],maxn=max(maxn,s[i]);
    for(int v=0;v<=20;++v){
        if((1<<v)>maxn)break;
        int cnt=0;
        memset(f,0,sizeof f);
        change(0,1,1);
        for(int i=1;i<=n;++i){
            int tmp=s[i]&((1<<v)-1),type=(s[i]>>v)&1;

            if(type)cnt+=sum(1,C-1)-sum(1,tmp+1)+sum(0,tmp+1);
            else cnt+=sum(0,C-1)-sum(0,tmp+1)+sum(1,tmp+1);
            change(type,tmp+1,1);
        }
        if(cnt%2)ans|=(1<<v);
    }

    printf("%lld",ans);
    return 0;
}