CF617E XOR and Favorite Number

BZOJ 5301 [CQOI2018]异或序列 双倍经验。

一个区间的异或值可以用前缀和来表示,$a_l \bigoplus a_{l + 1}\bigoplus a_{l + 2} \bigoplus ... \bigoplus a_r = xorSum_r \bigoplus xorSum_{l - 1}$,这样子处理一下异或前缀和用莫队移动一下左右端点就可以了。

要注意的一点就是左端点$l$在移动的时候其实不是在移动自己,每一次加入删除都是$l - 1$,因为不能取两个一样的下标异或起来算答案,所以在加入删除的时候要注意判断一下先后顺序。

时间复杂度$O(n\sqrt{n})$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;

const int N = 1e5 + 5;
const int M = 20;

int n, qn, K, blockSiz, a[N], sum[N];
ll nowAns = 0, cnt[1 << M];

struct Querys {
    int l, r, id;
    ll res;
    
    friend bool operator < (const Querys &x, const Querys &y) {
        if(x.l / blockSiz == y.l / blockSiz) return x.r < y.r;
        else return x.l < y.l;
    }
    
} q[N];

inline void read(int &X) {
    X = 0; char ch = 0; int op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void del(int now) {
    --cnt[sum[now]];
    nowAns -= cnt[sum[now] ^ K];
}

inline void add(int now) {
    nowAns += cnt[sum[now] ^ K];
    ++cnt[sum[now]];
}

inline void solve() {
    blockSiz = sqrt(n);
    sort(q + 1, q + 1 + qn);
    
/*    for(int i = 1; i <= qn; i++)
        printf("%d %d\n", q[i].l, q[i].r);   */
        
    cnt[0] = 1;
    for(int ln = 1, rn = 0, i = 1; i <= qn; i++) {
        for(; ln < q[i].l; del(ln - 1), ++ln);
        for(; ln > q[i].l; --ln, add(ln - 1));
        for(; rn < q[i].r; add(++rn));
        for(; rn > q[i].r; del(rn--));
        
        q[q[i].id].res = nowAns;
    }
}

int main() {
    read(n), read(qn), read(K);
    for(int i = 1; i <= n; i++) {
        read(a[i]);
        sum[i] = sum[i - 1] ^ a[i];
    }
    
/*    for(int i = 1; i <= n + 1; i++)
        printf("%d ", sum[i]);
    printf("\n");    */
    
    for(int i = 1; i <= qn; i++) {
        read(q[i].l), read(q[i].r);
        q[i].id = i;
    }
    
    solve();
    
    for(int i = 1; i <= qn; i++)
        printf("%lld\n", q[i].res);
        
    return 0;
} 
View Code

 

posted @ 2018-10-24 08:00  CzxingcHen  阅读(174)  评论(0编辑  收藏  举报