异或序列

题目描述

已知一个长度为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。

来源/分类

重庆OI2018 

首先题目让求的是a[l……r]=k的字序列有多少个
然后异或的性质 如果a^b=c 那么a^c=b
所以我们如果维护一下前缀异或和即为val[i],那么l到r的异或和就是val[r]^val[l-1],所以现在问题变成了找有多少对合法的l-1,r满足val[r]^val[l-1]=k 
还是不好做……
再考虑异或的性质,x^x^k=k  
所以说如果现在来了一个a[r]=x,我们想找在前面有多少个符合要求的l-1能使得val[l-1]^val[r]=k,那么显然val[r]=x^k,所以问题就变成了来了一个x,找他前面出现的x^k的个数。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+7;
int n,m,k,block;
int cnt[N],val[N];
int ans[N];
int tot;
struct orz
{
    int l,r,id;
    bool operator < (const orz &x) const
    {
        if (l/block==x.l/block) return r<x.r;
        return  l/block<x.l/block;
    }
}p[N];
void add(int x)
{
    tot+=cnt[x^k];cnt[x]++;
}
void del(int x)
{
    tot-=cnt[x^k];cnt[x]--;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    block=sqrt(n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
        val[i]=val[i-1]^val[i];
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&p[i].l,&p[i].r);
        p[i].l--;
        p[i].id=i;
    }
    sort(p+1,p+1+m);
    int l=1,r=0;
    for (int i=1;i<=m;i++)
    {
        while (l>p[i].l) add(val[--l]);
        while (l<p[i].l) del(val[l++]);
        while (r<p[i].r) add(val[++r]);
        while (r>p[i].r) del(val[r--]);
        ans[p[i].id]=tot;
    }
    for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2018-08-09 19:18  特特w  阅读(257)  评论(1编辑  收藏  举报