异或序列
题目描述
已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在al,al+1,…,ar区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足ax⊕ax+1⊕⋯⊕ay=k的x,y有多少组。
输入
输入第一行为3个整数n,m,k。第二行为空格分开的n个整数,即a1,a2,…,an。接下来m行,每行两个整数lj,rj,代表一次查询。
输出
输出共m行,对应每个查询的计算结果。
样例输入
4 5 1 1 2 3 1 1 4 1 3 2 3 2 4 4 4
样例输出
4 2 1 2 1
提示
对于30%的数据,1≤n,m≤1000。
对于100%的数据,1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n。
上来一看就是莫队,然而之后的事情却理解了好久
num[i]数组表示以i为异或和的数量
比如ans+=num[s[L]^k],表示我们现在R为结尾的是s[L],如果想要有一段区间为k,就是s[L-1]^s[R]=k
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long s[100005],num[100005],last[100005];
struct forma
{
int l,r,num;
}stu[100005];
int block;
bool cmp(forma a,forma b){
if(a.l/block==b.l/block)
return a.r<b.r;
return a.l<b.l;
}
int main()
{
int num2,qnum,k;
memset(s,0,sizeof(s));
memset(num,0,sizeof(num));
scanf("%d%d%d",&num2,&qnum,&k);
for(int i=1;i<=num2;i++)
scanf("%d",&s[i]);
for(int i=2;i<=num2;i++)
s[i]=s[i-1]^s[i];
for(int i=1;i<=qnum;i++){
int aa,bb;
scanf("%d%d",&aa,&bb);
stu[i].l=aa-1,stu[i].r=bb;
stu[i].num=i;
}
block=sqrt(num2);
sort(stu+1,stu+qnum,cmp);
int L=1,R=0;
long long ans=0;
for(int i=1;i<=qnum;i++){
while(R<stu[i].r){
R++;
ans+=num[s[R]^k];
num[s[R]]++;
}
while(L>stu[i].l){
L--;
ans+=num[s[L]^k];
num[s[L]]++;
}
while(R>stu[i].r){
ans-=num[s[R]^k];
num[s[R]]--;
R--;
}
while(L<stu[i].l){
ans-=num[s[L]^k];
num[s[L]]--;
L++;
}
last[stu[i].num]=ans;
}
for(int i=1;i<=qnum;i++){
printf("%lld\n",last[i]);
}
// system("Pause");
}