已知一个长度为 n 的整数数列 a[1],a[2],…,a[n] ,给定查询参数 l、r ,问在 [l,r] 区间内,有多少连续子
序列知足异或和等于 k 。
也就是说,对于全部的 x,y (l≤x≤y≤r),可以知足a[x]^a[x+1]^…^a[y]=k的x,y有多少组。spa
这样的题目首先按照异或运算前缀和,就变成屡次查询区间内有多少对数知足异或和为k.
考虑简单的状况.异或和为0的时候,就变成查询区间内有多少对数相同.这是很显然的莫队题目.
那么异或和为k的时候咱们也能够考虑莫队.比较简明的思路是用trie树维护区间内全部的数字,加入/删除数字的时候更新答案.
另外一种方式是,把全部的前缀和异或上k,组成另一个数列,那么对于询问的区间在原先的前缀和数列和异或k的前缀和数列上都有一个数集,而后找两个数集的相同的数对(就是找这样的数对:数值相同,可是一个数在这个数集,另外一个数在那个数集).code
#include<cstdio> #include<algorithm> using namespace std; const int maxn=100005; int a[maxn],s1[maxn],s2[maxn]; int cnt1[500000],cnt2[500000],ans; int SZ=250; struct query{ int l,r,num,ans; void read(){ scanf("%d%d",&l,&r);l--; } }Q[maxn]; bool cmp1(const query &A,const query &B){ if(A.l/SZ!=B.l/SZ)return A.l<B.l; return A.r<B.r; } void init(int l,int r){ //printf("%d %d\n",l,r); for(int i=l;i<=r;++i){ //printf("%d ",s1[i]); cnt1[s1[i]]++; }//printf("\n"); for(int i=l;i<=r;++i){ cnt2[s2[i]]++;//printf("%d ",s2[i]); ans+=cnt1[s2[i]]; }//printf("\n"); //printf("%d\n",ans); } void move(int l1,int r1,int l2,int r2){ for(int i=l1;i<l2;++i){ ans-=cnt2[s1[i]];ans-=cnt1[s2[i]]; cnt1[s1[i]]--;cnt2[s2[i]]--; if(s1[i]==s2[i])ans+=1; } for(int i=l1-1;i>=l2;--i){ ans+=cnt2[s1[i]];ans+=cnt1[s2[i]]; cnt1[s1[i]]++;cnt2[s2[i]]++; if(s1[i]==s2[i])ans-=1; } for(int i=r1+1;i<=r2;++i){ ans+=cnt2[s1[i]];ans+=cnt1[s2[i]]; cnt1[s1[i]]++;cnt2[s2[i]]++; if(s1[i]==s2[i])ans-=1; } for(int i=r1;i>r2;--i){ ans-=cnt2[s1[i]];ans-=cnt1[s2[i]]; cnt1[s1[i]]--;cnt2[s2[i]]--; if(s1[i]==s2[i])ans+=1; } } int res[maxn]; int main(){ int n,m,k;scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;++i){ scanf("%d",a+i); } for(int i=1;i<=n;++i)s1[i]=s1[i-1]^a[i]; for(int i=0;i<=n;++i)s2[i]=s1[i]^k; for(int i=1;i<=m;++i)Q[i].read(); for(int i=1;i<=m;++i)Q[i].num=i; sort(Q+1,Q+m+1,cmp1); init(Q[1].l,Q[1].r);Q[1].ans=ans; for(int i=2;i<=m;++i){ move(Q[i-1].l,Q[i-1].r,Q[i].l,Q[i].r); Q[i].ans=ans; } if(k==0){ for(int i=1;i<=m;++i)Q[i].ans-=(Q[i].r-Q[i].l+1); } for(int i=1;i<=m;++i)Q[i].ans/=2; for(int i=1;i<=m;++i)res[Q[i].num]=Q[i].ans; for(int i=1;i<=m;++i)printf("%d\n",res[i]); return 0; }