Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)

题目链接:http://codeforces.com/contest/617/problem/E

题目大意:有n个数和m次查询,每次查询区间[l, r]问满足ai ^ ai+1 ^ ... ^ aj == k的(i, j)  (l <= i <= j <= r)有多少对。

解题思路:先预处理出一个前缀异或和数组sum数组,则a[l]^a[l+1]^a[l+2]……^a[r]就等于sum[r]^sum[l-1]

然后我们采用莫队算法,用一个数组cnt数组记录前缀和出现的次数

我们要找之前有多少个前缀异或和与现在的前缀异或值为k,对应到cnt数组去找a[i]^k的个数,并更新答案就行了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1<<20;
ll pos[maxn],flag[maxn],ans[maxn];
int a[maxn];
struct node{
    int l,r,id;
}Q[maxn];
bool cmp(node a,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 L=1,R=0;
ll Ans=0;
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("%d",&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;
    sort(Q+1,Q+m+1,cmp);
    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){
            R++;
            add(R);
        }
        while(R>Q[i].r){
            del(R);
            R--;
        }
        ans[Q[i].id]=Ans;
    }
    for(int i=1;i<=m;i++)
    printf("%I64d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zjl192628928/p/11260537.html