码迷,mamicode.com
首页 > 其他好文 > 详细

[CQOI2018]异或序列 题解

时间:2019-09-11 18:20:16      阅读:20      评论:0      收藏:0      [点我收藏+]

标签:code   mes   clu   div   math   turn   sort   题意   nbsp   

转化题意

给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\n",ans[i]);
    }
    return 0;
}

 

[CQOI2018]异或序列 题解

标签:code   mes   clu   div   math   turn   sort   题意   nbsp   

原文地址:https://www.cnblogs.com/zrqlj/p/11507317.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!