codeforce617E-XOR and Favorite Number莫队+异或前缀和

传送门:http://codeforces.com/contest/617/problem/E

参考:https://blog.csdn.net/keyboarderqq/article/details/55807154

题意:
给出一系列数,对每个查询区间,计算有多少个子区间异或为k。
思路:


可以先预处理异或前缀,一个区间[L,R]的异或值=a[R]^a[L-1];

其中,a为异或前缀和数组;
如果当前区间是[A,B],加一个右端点B+1,那么这个 B+1 的贡献就是[A,B]区间内有多少个a[x] = a[B+1]^k
那么我们可以每次记录cnt[a[x]]即cnt[a[B+1]^k],并记录cnt[a[b+1]]++,同理左区间。

 

那么我们就可以使用莫队算法。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1<<20;

ll a[maxn], flag[maxn];
int pos[maxn];
ll Ans = 0;
ll res[maxn];
int m,n,k;

struct node {
    int l,r;
    int id;
}Q[maxn];

bool cmp(node a,node b)
{
    if(pos[a.l]==pos[b.l])
        return a.r < b.r;
    else return pos[a.l] < pos[b.l];
}

void add(int x)
{
    Ans += flag[a[x]^k];
    flag[a[x]]++;
}

void del(int x)
{
    flag[a[x]]--;
    Ans -= flag[a[x]^k];
}

int main(){
    scanf("%d%d%d", &n, &m, &k);
    int sz = sqrt(n);
    for(int i=1; i<=n; i++)
    {
        scanf("%I64d", &a[i]);
        a[i] = a[i-1] ^ a[i]; 
        pos[i] = (i-1) / sz + 1;
    }
    flag[0] = 1;
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&Q[i].l,&Q[i].r);
        Q[i].id = i;
    }
    sort(Q+1,Q+m+1,cmp);
    int l = 1,r = 0;
    for(int i=1; i<=m; i++)
    {
        while(l < Q[i].l){
            del(l-1);
            l++;
        }
        while(l > Q[i].l){
            l--;
            add(l-1);
        }
        while(r > Q[i].r){
            del(r);
            r--;
        }
        while(r < Q[i].r){
            r++;
            add(r);
        }
        res[Q[i].id] = Ans;
    }
    for(int i=1; i<=m; i++)
    {
        printf("%I64d\n",res[i]);
    }
    return 0;
}

 

posted @ 2018-04-25 16:20  ckxkexing  阅读(155)  评论(0编辑  收藏  举报