Codeforces 617EXOR and Favorite Number (Round #340 (Div. 2) E题) 莫队算法 + 异或基本性质

来源:互联网 发布:php开发app教程 编辑:程序博客网 时间:2024/05/21 01:28

题意

  • 给你一个数组和一个数k,然后有m个查询,每次给你l,r,问你[l , r]区间内有多少对(i,j),使得a[i] ^ a[i+1] … ^ a[j] = k

思路

  • pref[i]记录a[0] ^ a[1] ^ … ^a[i]的值
  • 区间[l, r]的解 = 统计(i, j)使得pref[i-1] ^ pref[j] = k的个数。(因为,a ^ b ^ a = b,所以所有小于i的数被以后两次后就相当于没被异或,而i~j则被异或了一次)
  • 然后,为了方便实现,我们换一种说法,相当于统计在[l-1, r]区间内有多少(i, j),使得pref[i] ^ pref[j] = k
  • 当然,因为有m个查询我们不能简单的暴力求解,所以这里用到了莫队算法
  • 这里给两个我自学时参考的文章:
  • http://wenku.baidu.com/link?url=id9fDlyKDaAINJtr6Iq3SYY97VOvec4cdo5QazWreZX3jCNFJU-gRZEreLicE2zoYWjpY4YCe1HmwewpH8bufjeb_aivNOuWcUp0HPlZzCi
  • http://blog.csdn.net/bossup/article/details/39236275
  • 基本想法就是,离线算法,存储所有的查询,然后对查询进行某种方法的排序,之后暴力的去算
  • 但是,这里的暴力也不太一样,是当算出了[l, r]区间的解后,左右移动l 和 r, 来算出[l’ , r’]的解
  • 所以,它要求我们可以很快的从[l, r]的解算出, [l-1, r], [l+1, r], [l, r-1], [l, r+1]的解
  • 这里用cnt数组来辅助,cnt[v] 表示 [l-1, r]区间内有cnt[v]个pref[i] = v的数, 然后我们就可以很快的算出刚才所述的解,具体方法,详见代码,要注意的是更新ans和cnt的顺序是有要求的,需要仔细考虑
  • 最后说个坑点,cnt数组不能开小了。。。因为1e6的数异或之后可不止1e6。。我居然被这个点坑了一个上午。。。

实现

#include <bits/stdc++.h>using namespace std;const int maxn = 2e6+6;typedef long long ll;const int B = 316; //316 < sqrt(1e5)int a[maxn];int pref[maxn];struct Node{    int l,r,id;}query[maxn];int cnt[maxn];ll Ans[maxn];bool cmp(Node x, Node y){    if (x.l / B != y.l / B)        return x.l < y.l;    return x.r < y.r;}int main(){    int n,m,k;    ios::sync_with_stdio(false);    cin>>n>>m>>k;    for (int i=1;i<=n;i++)    {        cin>>a[i];    }    for (int i=1;i<=n;i++){        pref[i] = a[i] ^ pref[i-1];    }    for (int i=0;i<m;i++){        int l,r;        cin>>query[i].l>>query[i].r;        query[i].id = i;    }    sort(query,query+m,cmp);    //这里可以让r = 0进行初始化    int l = 0, r = 1;    ll ans = a[1] == k ? 1 : 0;    cnt[pref[1]]++;    cnt[0]++;    for (int i=0; i < m; i++){        while (l < query[i].l - 1){            cnt[pref[l]]--;            ans -= (ll)cnt[pref[l] ^ k];            l++;        }        while (l > query[i].l - 1){            l--;            ans += (ll)cnt[pref[l] ^ k];            cnt[pref[l]]++;             }        while (r > query[i].r){            cnt[pref[r]]--;            ans -= (ll)cnt[pref[r] ^ k];            r--;        }        while (r < query[i].r){            r++;            ans += (ll)cnt[pref[r] ^ k];            cnt[pref[r]]++;        }        Ans[query[i].id] = ans;    }    for (int i=0;i<m;i++){        cout << Ans[i] << endl;    }    return 0;}
1 0
原创粉丝点击