「luogu4462」[CQOI2018] 异或序列

「luogu4462」[CQOI2018]异或序列

一句话题意

输入 \(n\) 个数,给定\(k\),共 \(m\) 组询问,输出第 \(i\) 组询问 \(l_i\) \(r_i\) 中有多少个连续子序列的异或和等于 \(k\)。数据范围均在 \([0,1e5]\)

本题不强制在线,故莫队。
记序列 \(a\) 的前缀异或和 \(pre\),用一个桶 \(t_i\) 记录当前查询区间内前缀异或和为 \(i\) 的数量。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
inline int in() {
    int x=0;char c=getchar();bool f=false;
    while(c<'0'||c>'9') f|=c=='-', c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
    return f?-x:x;
}

const int N = 1e5+5;

int n, m, k, cur, pre[N], t[N<<1], blo, bl[N], ans[N];

struct query {
    int l, r, id;
    inline friend bool operator < (const query &x, const query &y) {
        return bl[x.l]==bl[y.l]?x.r<y.r:x.l<y.l;
    }
}q[N];

inline void add(int u) {
    cur+=t[u^k];
    t[u]++;
}

inline void rem(int u) {
    t[u]--;
    cur-=t[u^k];
}

int main() {
    n=in(), m=in(), k=in();
    blo=(int)sqrt(n+1);
    for(int i=1;i<=n;++i) {
        bl[i]=(i-1)/blo+1;
        pre[i]=pre[i-1]^in();
    }
    for(int i=1;i<=m;++i) q[i]=(query){in()-1, in(), i};
    std::sort(q+1, q+1+m);

    for(int i=1, l=1, r=0;i<=m;++i) {
        for(;r<q[i].r;add(pre[++r]));
        for(;r>q[i].r;rem(pre[r--]));
        for(;l<q[i].l;rem(pre[l++]));
        for(;l>q[i].l;add(pre[--l]));
        ans[q[i].id]=cur;
    }
    for(int i=1;i<=m;++i) printf("%d\n", ans[i]);
    return 0;
}
posted @ 2019-03-12 17:46  15owzLy1  阅读(142)  评论(0编辑  收藏  举报