http://codeforces.com/contest/617/problem/E
题意就是给出n个数的序列和数字k,q次询问,每次询问给出[L,R],求这个区间内有多少个连续区间的异或和等于k。
由于我们知道
A[i]XorA[i+1]Xor....XorA[j]A[i]XorA[i+1]Xor....XorA[j]=(A[1]XorA[2]Xor.....A[i?1])Xor((A[1]XorA[2]Xor.....A[j])=(A[1]XorA[2]Xor.....A[i?1])Xor((A[1]XorA[2]Xor.....A[j]),
所以我们只要把原数组转为前缀异或和数组,问题就变为给定区间内有多少对i,j满足A[i]^A[j]=k.,所以add,del函数的写法就很明显了。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6+5;
struct node
{int l,r,id;
}Q[maxn];
int pos[maxn];
bool cmp(const node &a,const 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 flag[maxn];//数字在当前区间出现次数
int a[maxn];
ll ans[maxn];
int L=0,R=0;
ll Ans=0;void add(int x)
{Ans+=flag[a[x]^k];//a^b=c那么a^c=bflag[a[x]]++;//先统计答案再加,以免多算一次当前的x
}void del(int x)
{flag[a[x]]--;//先减再统计答案,以免多减当前的xAns-=flag[a[x]^k];//a^b=c那么a^c=b
}
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]^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;//没有数字的时后,表示前缀异或和为0sort(Q+1,Q+1+m,cmp);for(int i=1;i<=m;i++){while(R<Q[i].r){R++;add(R);}while(L+1>Q[i].l){L--;add(L);}while(L+1<Q[i].l){del(L);L++;}while(R>Q[i].r){del(R);R--;}ans[Q[i].id]=Ans;}for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);return 0;
}