[CQOI2018]异或序列 题解

Posted zrqlj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2018]异或序列 题解相关的知识,希望对你有一定的参考价值。

转化题意

给n个整数,给一个值k,m个询问,每个询问给出一个区间,求区间里有多少对数异或为k

 


注意到n个整数的值比较小,可以用桶存值的

我们用前缀异或和即可实现区间转化为数(满足区间减法即可

1n,m1e5,0k,值的大小1e5,

然后用莫队实现n sqrt(n),空间为o(值的大小)

操作:
分块排序,每次移动区间时

添加为存数并更新答案o(1)

删除为更新答案并删数o(1)


#include<bits/stdc++.h>
#define LL long long
#define IL inline
using namespace std;
const int N=100005;
int a[N],b[N];
int n,m,k;
struct modui{
    int l,r,id;
}q[N];
int cnt;
LL ans[N],ans0;
bool cmp(modui a,modui b){
    return a.l/cnt^b.l/cnt?a.l<b.l:a.r<b.r;
}
IL void add(int p){
    ans0+=b[a[p]^k];
    b[a[p]]++;
}
IL void del(int p){
    b[a[p]]--;
    ans0-=b[a[p]^k];
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    cnt=sqrt(n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=n;i++){
        a[i]^=a[i-1];
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].l--;
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmp);
    register int l=1,r=0;
    for(int i=1;i<=m;i++){
        while(l<q[i].l)del(l++);
        while(l>q[i].l)add(--l);
        while(r<q[i].r)add(++r);
        while(r>q[i].r)del(r--);
        ans[q[i].id]=ans0;
    }
    for(int i=1;i<=m;i++){
        printf("%lld
",ans[i]);
    }
    return 0;
}

 

以上是关于[CQOI2018]异或序列 题解的主要内容,如果未能解决你的问题,请参考以下文章

CQOI2018 异或序列 莫队+xor前缀和

[LuoguP4462][CQOI2018]异或序列

「luogu4462」[CQOI2018]异或序列

[CQOI2018] 异或序列

LuoguP4462 [CQOI2018]异或序列

Luogu P4462 [CQOI2018]异或序列