Codeforces Round #340 (Div. 2) E. XOR and Favorite Number(莫队+前缀异或)

给出数 n,m,k ,现在有 n 个数,m 此询问,每次询问给出 l,r 代表区间,求任意满足条件的的 l <= i <= j <= r 的 i ,j 使得 a[i]^a[i+1]^……a[j]=k,求可以找出多少对 <i,j> 这样的二元组

离线问题,我们采用莫队的方法来求解

但是想要求得任意一个区间的异或值比较困难,由异或运算可得 a^b=k  --->  k^b=a

所以每一次更新莫队时,例如添加一个数时,因为他不是在左端点添加就是在右端点添加,所以遍历当前区间即可

由于区间满足前缀和的性质,将 n 个数异或之后,因为异或运算满足两个相同的数相异或为 0 的性质,所以在添加任意一个数 i 时,相当于前缀 [1,i] 的异或总值,我们令其为 x

这样找到当前区间内 k^x 的个数即可,无论 i 是在区间的左边添加还是右边添加,答案要么是 [i+1,r] 要么是 [l+1,i] (l,r 为当前莫队的区间端点)

通俗来说就是   a[r]^a[l-1]=k \small \rightarrow a[l-1]=k^a[r] ,所以只要找出 a[l-1] 的个数即可,此时 a 数组表示异或前缀

所以我们将所给区间的左端点需做减一操作,即可解决此问题

当然这个题目还有一点小问题,从区间 [l,r] 任选两个数 i,j ,数据量会爆 int

处理前缀异或时,异或总值的大小最大为 (1<<20)-1

const int N=1e5+5;

    int i,j,k;
    int n,m,t;
    int a[N],block;
    struct Node
    {
        int id;
        int l,r,bel;
        bool operator<(Node o)
        {
            return bel^o.bel ? l<o.l : (bel&1 ? r<o.r : r>o.r );
        }
    }q[N];
    ll ans[N],cur,cnt[(int)1e7+5];

void add(int pos)
{
    int x=a[pos];
    cur+=cnt[x^k];
    cnt[x]++;
}

void del(int pos)
{
    int x=a[pos];
    cnt[x]--;
    cur-=cnt[x^k];
}

int main()
{
    //IOS;
    while(~sddd(n,m,k)){
        block=sqrt(n);
        for(int i=1;i<=n;i++) sd(a[i]),a[i]^=a[i-1];
        for(int i=1;i<=m;i++){
            sdd(q[i].l,q[i].r),q[i].id=i;
            q[i].l--;
            q[i].bel=q[i].l/block;
        }
        sort(q+1,q+1+m);
        int l=q[1].l,r=q[1].l-1; cur=0;
        for(int i=1;i<=m;i++){
            while(l>q[i].l) add(--l);
            while(l<q[i].l) del(l++);
            while(r>q[i].r) del(r--);
            while(r<q[i].r) add(++r);
            ans[q[i].id]=cur;
        }
        for(int i=1;i<=m;i++) pll(ans[i]);
    }
    //PAUSE;
    return 0;
}

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页