题目:luogu CF 617 E.
题目大意:给出一串数列a,以及一些询问[l,r]内的有多少的子段[i,j]使ai xor ai+1 xor...xor aj=k,k为固定常数.
题目好像是离线的,而且没有修改操作,所以这道题可以使用莫队.
我们可以考虑,如何用区间[l,r]的种数获得[l-1,r]的种数以及[l,r+1]的种数.
我们知道,异或的逆运算是异或,也就是说我们可以通过ai xor...xor aj和aj+1知道ai xor...xor aj+1,也可以用ai xor...xor aj+1和aj+1知道ai xor...xor aj.
具体细节看代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=100000; struct seg{ int l,r,in,id; }e[N+1]; LL ans[N+1],cnt[N*20+1],now; int l,r,a[N+1],n,m,k; inline void into(){ scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]^=a[i-1]; } for (int i=1;i<=m;i++){ scanf("%d%d",&e[i].l,&e[i].r); e[e[i].id=i].in=e[i].l+1>>9; //以512个元素为一个块 } } bool cmp(seg a,seg b){ return a.in<b.in||a.in==b.in&&a.r<b.r; } void get(int x,long long num){ //注意这里要开long long now+=num*cnt[a[x]^k]; cnt[a[x]]+=num; if (num==-1&&k==0) ++now; } inline void work(){ sort(e+1,e+1+m,cmp); r=l=1;++cnt[a[1]],++cnt[0]; if (a[1]==k) now=1; else now=0; for (int i=1;i<=m;i++){ while (l>e[i].l) --l,get(l-1,1); while (l<e[i].l) get(l-1,-1),l++; while (r>e[i].r) get(r--,-1); while (r<e[i].r) get(++r,1); ans[e[i].id]=now; } } inline void outo(){ for (int i=1;i<=m;i++) printf("%lld\n",ans[i]); } int main(){ into(); work(); outo(); return 0; }