P4462 [CQOI2018]异或序列
Problem:
https://www.luogu.com.cn/problem/P4462
Solution:
求出异或前缀和sum[],对于 a[ l ] ^ a[ l + 1] ^ .... ^ a[ r ] 就变成了sum[ r ] ^ sum[ l - 1 ],所以最终我们要求的就是在区间 [ L,R ] 中有多少子区间 [ l,r ] 是满足 sum[ r ] ^ sum[ l - 1 ] = k 的(sum[ r ] ^ sum[ l - 1 ] = k 《==》sum[ l - 1 ] = sum[ r ] ^ k 《==》sum[ r ] = k ^ sum[ l - 1 ]),变换以下就是求 [ l - 1,r ] 区间有多少个数是等于k ^ sum[ x ] (ps:x 是当前区间中新加入的数)
因此题目就变成了区间记数问题,而题目中可以离线处理,所以我们就可以用莫队来写。
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define _for(i,s,t) for(int i=s;i<t;i++) #define _rof(i,s,t) for(int i=s;i>t;i--) #define rep(i,s,t) for(int i=s;i<=t;i++) #define per(i,s,t) for(int i=s;i>=t;i--) #define Ri(x) scanf("%d",&x) #define Rii(x,y) scanf("%d%d",&x,&y) #define INF 0x3f3f3f3f using namespace std; template<class T>inline void read(T &res) { char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; } typedef long long ll; const int maxn = 1e5 + 10; int a[maxn],ans[maxn],cnt[maxn],block; struct Node{ int l,r,i; friend bool operator < (Node n1,Node n2){ if(n1.l/block != n2.l/block) return n1.l < n2.l; return n1.r < n2.r; } }nd[maxn]; int main(){ IOS; int n,m,k,v; cin>>n>>m>>k; block = sqrt(n); rep(i,1,n){ cin>>v; a[i] = a[i - 1] ^ v; } rep(i,1,m){ cin>>nd[i].l>>nd[i].r; nd[i].i = i;nd[i].l --; } sort(nd + 1,nd + 1 + m); int l = 1,r = 0,num = 0; rep(i,1,m){ while(r < nd[i].r){ ++r; num += cnt[a[r] ^ k]; ++cnt[a[r]]; } while(r > nd[i].r){ --cnt[a[r]]; num -= cnt[a[r] ^ k]; --r; } while(l < nd[i].l){ --cnt[a[l]]; num -= cnt[a[l] ^ k]; ++l; } while(l > nd[i].l){ --l; num += cnt[a[l] ^ k]; ++cnt[a[l]]; } ans[nd[i].i] = num; } rep(i,1,n){ cout<<ans[i]<<endl; } return 0; }