异或序列
题目描述
已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在al,al+1,…,ar区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足ax⊕ax+1⊕⋯⊕ay=k的x,y有多少组。
输入
输入第一行为3个整数n,m,k。第二行为空格分开的n个整数,即a1,a2,…,an。接下来m行,每行两个整数lj,rj,代表一次查询。
输出
输出共m行,对应每个查询的计算结果。
样例输入
4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4
样例输出
4
2
1
2
1
提示
对于30%的数据,1≤n,m≤1000。
对于100%的数据,1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n。
来源/分类
首先题目让求的是a[l……r]=k的字序列有多少个 然后异或的性质 如果a^b=c 那么a^c=b 所以我们如果维护一下前缀异或和即为val[i],那么l到r的异或和就是val[r]^val[l-1],所以现在问题变成了找有多少对合法的l-1,r满足val[r]^val[l-1]=k 还是不好做…… 再考虑异或的性质,x^x^k=k 所以说如果现在来了一个a[r]=x,我们想找在前面有多少个符合要求的l-1能使得val[l-1]^val[r]=k,那么显然val[r]=x^k,所以问题就变成了来了一个x,找他前面出现的x^k的个数。
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e6+7; int n,m,k,block; int cnt[N],val[N]; int ans[N]; int tot; struct orz { int l,r,id; bool operator < (const orz &x) const { if (l/block==x.l/block) return r<x.r; return l/block<x.l/block; } }p[N]; void add(int x) { tot+=cnt[x^k];cnt[x]++; } void del(int x) { tot-=cnt[x^k];cnt[x]--; } int main() { scanf("%d%d%d",&n,&m,&k); block=sqrt(n); for (int i=1;i<=n;i++) { scanf("%d",&val[i]); val[i]=val[i-1]^val[i]; } for (int i=1;i<=m;i++) { scanf("%d%d",&p[i].l,&p[i].r); p[i].l--; p[i].id=i; } sort(p+1,p+1+m); int l=1,r=0; for (int i=1;i<=m;i++) { while (l>p[i].l) add(val[--l]); while (l<p[i].l) del(val[l++]); while (r<p[i].r) add(val[++r]); while (r>p[i].r) del(val[r--]); ans[p[i].id]=tot; } for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }