1. 程式人生 > >BZOJ5301:[CQOI2018]異或序列——題解

BZOJ5301:[CQOI2018]異或序列——題解

博客 參數 size isdigit 之前 我的博客 代碼 using clu

https://www.lydsy.com/JudgeOnline/problem.php?id=5301

https://www.luogu.org/problemnew/show/P4462

已知一個長度為 n 的整數數列 a[1],a[2],…,a[n] ,給定查詢參數 l、r ,問在 [l,r] 區間內,有多少連續子序列滿足異或和等於 k 。 也就是說,對於所有的 x,y (l≤x≤y≤r),能夠滿足a[x]^a[x+1]^…^a[y]=k的x,y有多少組。

開始時還在想怕不是一棵主席樹(滑稽)。

想多了,莫隊足以解決。

為了方便求區間異或和,把a處理為前綴異或和。

剩下的看代碼吧,不太好說,就是註意左端點的移動是要把它之前的點增/刪,因為l~r的異或=a[r]^a[l-1]。

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+5;
inline int read(){
    int
X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==-;ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct qu{ int pos,l,r; }q[N]; int a[N],ans[N],cnt[N],sum,n,m,k,s; inline int bel(int x){return (x-1)/s+1;} bool cmp(qu b,qu c){
return bel(b.l)==bel(c.l)?b.r<c.r:b.l<c.l; } inline void add(int x){ sum+=cnt[x^k]; cnt[x]++; } inline void del(int x){ cnt[x]--; sum-=cnt[x^k]; } int main(){ n=read(),m=read(),k=read(); s=sqrt(n); for(int i=1;i<=n;i++)a[i]=a[i-1]^read(); for(int i=1;i<=m;i++){ q[i].pos=i;q[i].l=read();q[i].r=read(); } sort(q+1,q+m+1,cmp); int ql=1,qr=0;cnt[0]++; for(int i=1;i<=m;i++){ while(qr<q[i].r)add(a[++qr]); while(qr>q[i].r)del(a[qr--]); while(ql<q[i].l)del(a[ql-1]),ql++; while(ql>q[i].l)ql--,add(a[ql-1]); ans[q[i].pos]=sum; } for(int i=1;i<=m;i++)printf("%d\n",ans[i]); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

BZOJ5301:[CQOI2018]異或序列——題解