P4462 异或序列 莫队 + 异或技巧

传送门
题意:给定一个k,一段序列。有m个询问,每次给定 [ l , r ] ,询问该区间内,有多少子序列满足异或和等于k。

以下数组 x 为当前点的 value, a 为 x 的前缀异或和。

看到区间异或和,不由的想到可以转换成前缀异或:a( l ) ^ a( l + 1 ) ^ … ^ a( r ) == a( l - 1 ) ^ a( r ) ,现在问题转换成了在 [ l , r ] 内是否存在两个数异或等于k。也就是 a [ x ] ^ a [ y ] = k 。让后看到了这个式子之后还是有点不可做,比如当前区间是 [ l , r ] ,要加上 x [ r + 1 ] 这个数,怎么找另外一个 [ l , r ] 内的数与它异或为 k 的 a [ x ] 呢?显然可以将两边异或a [ r + 1 ],通过 a [ x ] = a [ r + 1 ] ^ k 得到。剩下的就比较简单了,用一个桶记录一下异或值的个数,直接操作即可。

闲的没事加了一些优化,不加也能过。

#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define pb push_back
#define mk make_pair
#define il inline
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,m,k;
int cnt[N],id[N],a[N],ans[N],res;
int now;
struct Node
{
    int l,r;
    int id;
}q[N];

template <class T>
bool read(T &ret)//输入
{
    char c;
    int sgn;
    T bit=0.1;
    if(c=getchar(), c==EOF)
        return 0;
    while(c!='-' && c!='.' && (c<'0' || c>'9'))
        c=getchar();
    sgn=(c=='-')? -1:1;
    ret=(c=='-')? 0:(c-'0');
    while(c=getchar(), c>='0' && c<='9')
        ret=ret*10+(c-'0');
    if(c==' ' || c=='\n')
    {
        ret*=sgn;
        return 1;
    }
    while(c=getchar(), c>='0' && c<='9')
        ret+=(c-'0')*bit, bit/=10;
    ret*=sgn;
    return 1;
}

inline void out(int x)//输出
{
    if(x>9)
        out(x/10);
    putchar(x%10+'0');
}

bool cmp(Node a,Node b)
{
    return id[a.l]^id[b.l]? id[a.l]<id[b.l] : ((id[a.l]&1)? a.r>b.r : a.r<b.r);
}

il void del(int x)
{
    x=a[x];
    cnt[x]--;
    res-=cnt[x^k];
}

il void add(int x)
{
    x=a[x];
    res+=cnt[x^k];
    cnt[x]++;
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    read(n),read(m),read(k);
    int se=sqrt(n);
    se=ceil((double)n/se);
    for(int i=1;i<=n;i++)
    {
        read(a[i]),a[i]^=a[i-1];
        id[i]=(i-1)/se+1;
    }
    for(int i=1;i<=m;i++)
    {
        read(q[i].l); read(q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmp);
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        int lx=q[i].l-1,rx=q[i].r;
        while(l<lx) del(l++);
        while(l>lx) add(--l);
        while(r>rx) del(r--);
        while(r<rx) add(++r);
        ans[q[i].id]=res;
    }
    for(int i=1;i<=m;i++) out(ans[i]),putchar('\n');





	return 0;
}
/*

*/









猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/108342371