6759: 异或序列
时间限制: 1 Sec 内存限制: 128 MB
提交: 191 解决: 88
[提交] [状态] [讨论版] [命题人:admin]
题目描述
已知一个长度为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。
来源/分类
分析:借这个题讲一下稍微说一下莫队吧,看了几篇博客略有感悟。这个题看明白了就是一道裸莫队板子。
1、首先处理异或前缀和 a。
2、假设i到j的异或和为k,那么有a[i-1]^a[j]=k。同样也有a[j]^k=a[i-1]和a[i-1]^k=a[j]。
3、利用s[i]记录前缀和为i的有几个,那么对于当前扫到的位置x明显答案就是ans+=s[a[x]^k],同时s[a[x]]++。同样如果询问范围不在x里了要减去。
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<deque>
#include<ctype.h>
#include<map>
#include<set>
#include<stack>
#include<string>
#define INF 100
#define FAST_IO ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MAX=1e5+10;
const int mod=1e9+7;
typedef long long ll;
using namespace std;
#define gcd(a,b) __gcd(a,b)
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t);b>>=1;t=(t*t);}return r;}
inline ll inv1(ll b){return qpow(b,mod-2);}
inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll r=exgcd(b,a%b,y,x);y-=(a/b)*x;return r;}
inline ll read(){ll x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
struct node
{
int id,l,r;
int block;
}mo[MAX];
int sum[MAX];
int n,m,k,len,res;
int a[MAX],ans[MAX];
int s[MAX];
int cmp(node a,node b)
{
if(a.block==b.block)
return a.r<b.r;
return a.block<b.block;
}
void add(int x)
{
res+=s[a[x]^k];
s[a[x]]++;
}
void del(int x)
{
res-=s[a[x]^k];
s[a[x]]--;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]=a[i]^a[i-1];
}
len=sqrt(n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&mo[i].l,&mo[i].r);
mo[i].l--;
mo[i].id=i;
mo[i].block=mo[i].l/len;
}
sort(mo+1,mo+1+n,cmp);
int left=1,right=0;
for(int i=1;i<=m;i++)
{
while(right<mo[i].r) add(++right);///询问范围大于已经扫到的范围。
while(left>mo[i].l) add(--left);
while(mo[i].r<right) del(right--);///询问范围小于已经扫到的范围。
while(mo[i].l>left) del(left++);
ans[mo[i].id]=res;
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}