[CQOI2018]异或序列 题解

转化题意

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

 


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

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

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

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

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

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

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


#include
#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.lb.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);
        while(l>q[i].l)add(--l);
        while(rr);
        while(r>q[i].r)del(r--);
        ans[q[i].id]=ans0;
    }
    for(int i=1;i<=m;i++){
        printf("%lld\n",ans[i]);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/zrqlj/p/11507317.html

你可能感兴趣的:([CQOI2018]异或序列 题解)