【CQOI2018】异或序列 - 莫队

题目描述

已知一个长度为n的整数数列 $a_1,a_2,...,a_n$​,给定查询参数l、r,问在 $a_l,a_{l+1},...,a_r$​ 区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y (I ≤ x ≤ y ≤ r),能够满足$a_x\bigoplus a_{x+1} \bigoplus ... \bigoplus a_y = k$的x,y有多少组。

输入输出格式

输入格式:

输入文件第一行,为3个整数n,m,k。

第二行为空格分开的n个整数,即$a_1,a_2,..a_n$​ 。

接下来m行,每行两个整数 $l_j,r_j$​ ,表示一次查询。

输出格式:

输出文件共m行,对应每个查询的计算结果。

 

思路

记一个异或前缀和  val,问题就转换成有多少对数异或等于 k

直接上莫队

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int n,m,k,block,cnt[maxn],val[maxn];
long long tot,ans[maxn];
struct Query {
    int l,r,num;
    inline bool operator < (Query cmp) const {
        if (l/block != cmp.l/block) return l/block < cmp.l/block;
        return r/block < cmp.r/block;
    }
}q[maxn];
inline void add(int x) { tot += cnt[x^k]; cnt[x]++; }
inline void del(int x) { tot -= cnt[x^k]+(!k); cnt[x]--; }
int main() {
    scanf("%d%d%d",&n,&m,&k);
    block = sqrt(n);
    for (int i = 1;i <= n;i++) scanf("%d",&val[i]),val[i] ^= val[i-1];
    for (int i = 1;i <= m;i++) {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].l--;
        q[i].num = i;
    }
    sort(q+1,q+m+1);
    int l = 1,r = 0;
    for (int i = 1;i <= m;i++) {
        while (l > q[i].l) add(val[--l]);
        while (l < q[i].l) del(val[l++]);
        while (r < q[i].r) add(val[++r]);
        while (r > q[i].r) del(val[r--]);
        ans[q[i].num] = tot;
    }
    for (int i = 1;i <= m;i++) printf("%lld\n",ans[i]);
    return 0;
}

 

posted @ 2018-05-03 16:23 lrj124 阅读(...) 评论(...) 编辑 收藏