Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)
题目链接:http://codeforces.com/contest/617/problem/E
题目大意:有n个数和m次查询,每次查询区间[l, r]问满足ai ^ ai+1 ^ ... ^ aj == k的(i, j) (l <= i <= j <= r)有多少对。
解题思路:先预处理出一个前缀异或和数组sum数组,则a[l]^a[l+1]^a[l+2]……^a[r]就等于sum[r]^sum[l-1]
然后我们采用莫队算法,用一个数组cnt数组记录前缀和出现的次数
我们要找之前有多少个前缀异或和与现在的前缀异或值为k,对应到cnt数组去找a[i]^k的个数,并更新答案就行了。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1<<20; ll pos[maxn],flag[maxn],ans[maxn]; int a[maxn]; struct node{ int l,r,id; }Q[maxn]; bool cmp(node a,node b){ if(pos[a.l]==pos[b.l]) return a.r<b.r; return pos[a.l]<pos[b.l]; } int n,m,k; int L=1,R=0; ll Ans=0; void add(int x){ Ans+=flag[a[x]^k]; flag[a[x]]++; } void del(int x){ flag[a[x]]--; Ans-=flag[a[x]^k]; } int main(){ scanf("%d%d%d",&n,&m,&k); int sz=sqrt(n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]^=a[i-1]; pos[i]=i/sz; } for(int i=1;i<=m;i++){ scanf("%d%d",&Q[i].l,&Q[i].r); Q[i].id=i; } flag[0]=1; sort(Q+1,Q+m+1,cmp); for(int i=1;i<=m;i++){ while(L<Q[i].l){ del(L-1); L++; } while(L>Q[i].l){ L--; add(L-1); } while(R<Q[i].r){ R++; add(R); } while(R>Q[i].r){ del(R); R--; } ans[Q[i].id]=Ans; } for(int i=1;i<=m;i++) printf("%I64d\n",ans[i]); return 0; }