codeforces 617 E. XOR and Favorite Number(莫队)

来源:互联网 发布:西南大学远程网络教育 编辑:程序博客网 时间:2024/06/05 00:11

题意:

n个数,m个区间,问区间内有多少对(i,j)a[i]^a[i+1]^......a[j-1]^a[j]==k,k已给出。


解题思路:

离线的查询,用莫队最好了。

第一次写莫队,所以理解还比较浅。

莫队算法的原理是基于由已知[l,r]的答案推到[l,r-1],[l-1, r],[l, r+1], [l+1, r]的答案是o(1)的,所以我们可以先算出一个区间的答案,然后再逐步由此去求出其它区间的答案,步数是两个区间的曼哈顿距离(把区间看成点的话),这样做的话极限数据是会卡tle的。

然后莫队优化的地方就是在于把询问区间按左端点分块了,然后排序,让左端点坐在的块的编号小的在前面,相等的时候让右端点小的在前面。

这样的话,由i区间移动到i+1区间,左端点的移动就肯定不会超过sqrt(n)了

右端点的话,在一个块内是单调递增的,在一个递增区间内r的差距最大为n,且只会出现一次,因为 单调,然后总共有n^0.5块,所以右端点的总更新时间也不会超过o(nsqrt(n)).

    跨越一个块的话,差距也最多是n,且每两个相邻的块只会出现一次,总共有n^0.5块,所以更新的时间复杂度是o(nsqrt(n));


然后这个题具体来讲需要讲一下的时候add函数和del函数了,在代码里讲吧。


代码:

#include <bits/stdc++.h>#define LL long longusing namespace std;const int maxn=1<<20;struct p{    int l, r, id;}block[maxn];int pos[maxn];LL book[maxn];int n, m, k;LL ANS=0;LL ans[maxn];int a[maxn];bool cmp(p a, p b){    if(pos[a.l]==pos[b.l])    {        return a.r<b.r;    }    else return pos[a.l]<pos[b.l];}int L=1, R=0;void del(int x){    book[a[x]]--;    //book是统计1,i区间值为y的区间有多少个,这里x点删去,就删去对应的值    ANS-=book[a[x]^k];   //[i,j]异或值为a[j]^a[i],book[a[x]^k]就是询问有多少个a[i]的值为a[x]^k,对应的就是[i,x]值为k的有多少对,也就是x对应的答案了,这里需要减去x对应的答案}void add(int x){    ANS+=book[a[x]^k];    book[a[x]]++;}int main(){    int i, j;    cin>>n>>m>>k;    int sz=sqrt(n);    for(i=1; i<=n; i++)    {        scanf("%d", &a[i]);        a[i]=a[i]^a[i-1];        pos[i]=i/sz;    }    for(i=1; i<=m; i++)    {        scanf("%d%d", &block[i].l, &block[i].r);        block[i].id=i;    }    sort(block+1, block+m+1, cmp);    book[0]=1;    for(i=1; i<=m; i++)    {        while(L<block[i].l)        {            del(L-1);            L++;        }        while(L>block[i].l)        {            L--;            add(L-1);        }        while(R>block[i].r)        {            del(R);            R--;        }        while(R<block[i].r)        {            R++;            add(R);        }        ans[block[i].id]=ANS;    }    for(i=1; i<=m; i++)printf("%lld\n", ans[i]);        }


原创粉丝点击