P4462 [CQOI2018] 异或序列

· · 题解

P4462 [CQOI2018] 异或序列

题目翻译:

本题题意还算时比较简单明了的,我就不翻译了

思路:

$2.$ 根据上面性质可以发现最终要求的就是有多少 $r,l-1$ 可以使 $r \bigoplus l-1=k$ 又因为 $x \bigoplus y=k \rightarrow x \bigoplus k=y$ 因此可以用莫队来求解,答案增删的值就转换为当前增删点与 $k$ 异或的个数,用一个 $tot[i]$ 数组表示该前缀异或和数的个数,$sum[i]$ 表示前缀异或和。 ```cpp int cnt,tot[2*N],k; void add(int x){ cnt+=tot[sum[x]^k]; tot[sum[x]]++; } void del(int x){ tot[sum[x]]--; cnt-=tot[sum[x]^k]; } ``` $3.$ **注意**:由于是前缀异或和,所有的 $l$ 都要减一 # 完整代码: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5+5; int a[N],sum[N],ans[N]; struct query{ int l,r,id; }q[N]; int len; bool cmp(query x,query y){ if(x.l/len!=y.l/len)return x.l<y.l; else if((x.l/len)&1)return x.r<y.r; else return x.r>y.r; } int cnt,tot[2*N],k; void add(int x){ cnt+=tot[sum[x]^k]; tot[sum[x]]++; } void del(int x){ tot[sum[x]]--; cnt-=tot[sum[x]^k]; } signed main(){ int n,m; scanf("%lld%lld%lld",&n,&m,&k); len=sqrt(n); for(int i=1;i<=n;i++){ scanf("%lld",&sum[i]); sum[i]^=sum[i-1]; } for(int i=1;i<=m;i++){ int l,r; scanf("%lld%lld",&l,&r); q[i]={l,r,i}; } sort(q+1,q+m+1,cmp); int l=1,r=0; for(int i=1;i<=m;i++){ int ll=q[i].l-1; int rr=q[i].r; while(l<ll)del(l++); while(l>ll)add(--l); while(r<rr)add(++r); while(r>rr)del(r--); ans[q[i].id]=cnt; } for(int i=1;i<=m;i++){ printf("%lld\n",ans[i]); } } ``` ## [莫队讲解](https://www.luogu.com.cn/article/bow29afg)