题解 P4462 【[CQOI2018]异或序列】
解法:
维护一个异或前缀和序列,表示1到i的异或和,之后问题就变成了:区间
代码:
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int l,h,r;
}q[100001];
int o[200001],bl[100001],n,m,ans,r; //o[i]表示当前区间有多少个数异或和为i
int a[100001],num[100001],k,blo,l;
inline bool cmp(node c,node d){
if (bl[c.l]!=bl[d.l]) return c.l<d.l;
if (bl[c.l]&1) return c.r<d.r; return c.r>d.r;
}
inline void add(int x){ans+=o[a[x]^k]; o[a[x]]++;}
inline void del(int x){o[a[x]]--; ans-=o[k^a[x]];}
int main(){
scanf("%d%d%d",&n,&m,&k); blo=sqrt(n);
for (int i=1; i<=n; i++){
scanf("%d",&a[i]);
bl[i]=(i-1)/blo+1;
a[i]=a[i-1]^a[i];
}
for (int i=1; i<=m; i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].h=i; q[i].l--;
}
sort(q+1,q+m+1,cmp); l=1;
for (int i=1; i<=m; i++){
while (l>q[i].l) l--,add(l);
while (l<q[i].l) del(l),l++;
while (r<q[i].r) r++,add(r);
while (r>q[i].r) del(r),r--;
num[q[i].h]=ans;
}
for (int i=1; i<=m; i++) printf("%d\n",num[i]);
return 0;
}
2019/1/15 update:
被 @NaCly_Fish 神仙hack掉了,原先的题解中del函数有问题,应改成这样:
inline void del(int x){o[a[x]]--; ans-=o[k^a[x]];}
写的时候为了好看没过脑子就写上了