【Codeforces Round #340 (Div. 2), problem: (E) XOR and Favorite Number】 莫队算法

http://codeforces.com/contest/617/problem/E
题意就是给出n个数的序列和数字k,q次询问,每次询问给出[L,R],求这个区间内有多少个连续区间的异或和等于k。
由于我们知道
A [ i ] X o r A [ i + 1 ] X o r . . . . X o r A [ j ] = ( A [ 1 ] X o r A [ 2 ] X o r . . . . . A [ i 1 ] ) X o r ( ( A [ 1 ] X o r A [ 2 ] X o r . . . . . A [ j ] )
所以我们只要把原数组转为前缀异或和数组,问题就变为给定区间内有多少对i,j满足A[i]^A[j]=k.,所以add,del函数的写法就很明显了。
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6+5;
struct node
{
    int l,r,id;
}Q[maxn];
int pos[maxn];
bool cmp(const node &a,const node &b)
{
    if(pos[a.l]==pos[b.l])
        return a.r<b.r;
    return pos[a.l]<pos[b.l];
}
int n,m,k;
int flag[maxn];//数字在当前区间出现次数
int a[maxn];
ll ans[maxn];
int L=0,R=0;
ll Ans=0;

void add(int x)
{
    Ans+=flag[a[x]^k];//a^b=c那么a^c=b
    flag[a[x]]++;//先统计答案再加,以免多算一次当前的x
}

void del(int x)
{
    flag[a[x]]--;//先减再统计答案,以免多减当前的x
    Ans-=flag[a[x]^k];//a^b=c那么a^c=b
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int sz=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        a[i]=a[i]^a[i-1];//数组转为前缀异或和数组
        pos[i]=i/sz;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&Q[i].l,&Q[i].r);
        Q[i].id=i;
    }
    flag[0]=1;//没有数字的时后,表示前缀异或和为0
    sort(Q+1,Q+1+m,cmp);
    for(int i=1;i<=m;i++)
    {
         while(R<Q[i].r)
        {
            R++;
            add(R);
        }
        while(L+1>Q[i].l)
        {
            L--;
            add(L);
        }
        while(L+1<Q[i].l)
        {
            del(L);
            L++;
        }
        while(R>Q[i].r)
        {
            del(R);
            R--;
        }
        ans[Q[i].id]=Ans;
    }
    for(int i=1;i<=m;i++)
        printf("%lld\n",ans[i]);
    return 0;
}

友情推荐莫队算法专题链接

猜你喜欢

转载自blog.csdn.net/qq_38891827/article/details/82192867