CF617E XOR and Favorite Number

题目描述

  • 给定一个长度为 \(n\) 的序列 \(a\),然后再给一个数字 \(k\),再给出 \(m\) 组询问,每组询问给出一个区间,求这个区间里面有多少个子区间的异或值为 \(k\)
  • \(1 \le n,m \le 10 ^ 5\)\(0 \le k,a_i \le 10^6\)\(1 \le l_i \le r_i \le n\)

样例 #1

样例输入 #1

6 2 3
1 2 1 1 0 3
1 6
3 5

样例输出 #1

7
0

样例 #2

样例输入 #2

5 3 1
1 1 1 1 1
1 5
2 4
1 3

样例输出 #2

9
4
4

分析

首先可以使用前缀异或和 \(O(1)\) 求出区间异或和,接下来考虑扩展区间的情况。

假设现在区间为 \([l,r]\),加一个右端点 \(r+1\),那么区间 \([l,r]\) 中有多少个 \(a[x]^a[r+!]=k\),就是答案所新加的贡献值。

又因为异或的性质 \(a[x]=k^a[r+1]\),而 \(a[x]\) 在当前区间的个数又可以用桶来维护,且允许离线处理,可以十分简单的使用莫队。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,bl,num,a[1000005],b[1000005],ans[1000005],cnt[2000005];
struct node{
	int l,r,id;
}q[1000005];
bool cmp(node x,node y){return b[x.l]^b[y.l]?b[x.l]<b[y.l]:(b[x.l]&1?x.r<y.r:x.r>y.r);}
signed main(){
	cin>>n>>m>>k;
	bl=n/sqrt((m<<1)/3)+1;
	for(int i=1;i<=n;i++)cin>>a[i],b[i]=(i-1)/bl+1,a[i]^=a[i-1];
	for(int i=1;i<=m;i++)cin>>q[i].l>>q[i].r,q[i].id=i,q[i].l--;
	sort(q+1,q+m+1,cmp);
	for(int i=1,l=1,r=0;i<=m;i++){
		while(l>q[i].l)num+=cnt[a[--l]^k],++cnt[a[l]];
		while(l<q[i].l)--cnt[a[l]],num-=cnt[a[l++]^k];
		while(r<q[i].r)num+=cnt[a[++r]^k],++cnt[a[r]];
		while(r>q[i].r)--cnt[a[r]],num-=cnt[a[r--]^k];
		ans[q[i].id]=num;
	}
	for(int i=1;i<=m;i++)cout<<ans[i]<<endl;
	return 0;
}
posted @ 2023-06-24 19:41  alex_liu09  阅读(9)  评论(0)    收藏  举报