时间限制: 1 Sec 内存限制: 128 MB
题目描述
已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在al,al+1,…,ar区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足ax⊕ax+1⊕⋯⊕ay=k的x,y有多少组。
输入
输入第一行为3个整数n,m,k。第二行为空格分开的n个整数,即a1,a2,…,an。接下来m行,每行两个整数lj,rj,代表一次查询。
输出
输出共m行,对应每个查询的计算结果。
样例输入
4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4
样例输出
4
2
1
2
1
提示
对于30%的数据,1≤n,m≤1000。
对于100%的数据,1≤n,m≤10^5,0≤k,ai≤10^5,1≤lj≤rj≤n。
来源/分类
重庆OI2018
Solution
讲m种询问离线下来,分区,x=sqrt(m),按照分区标号从小到大,同一小区间r从小到大排序;
借助异或前缀和,sum[i]=sum[i-1]^a[i],之后有a[l]^a[l+1]^…^a[r]=sum[r]^sum[l-1];
此处[curL,curR]是闭区间。
——鄙人手中的第二个莫队代码
#include<bits/stdc++.h>
#define ll long long
#define L(u) u<<1
#define R(u) u<<1|1
using namespace std;
const int MX = 100001;
int n, m, k;
int a[MX], s[MX<<1];
int x, curL, curR, res;
int pos[MX];
ll ans[MX];
struct data {
int L, R, id;
bool operator<(const data &b) const {
if (pos[L] == pos[b.L]) return R < b.R;
return L < b.L;
}
} q[MX];
inline void add(int p) {
s[a[p]]++;
res += s[a[p]^k];
}
inline void del(int p) {
res -= s[a[p]^k];
s[a[p]]--;
}
inline void addL(int l, int r) {}
inline void delL(int l, int r) {}
inline void addR(int l, int r) {}
inline void delR(int l, int r) {}
int main() {
//freopen("../in", "r", stdin);
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
a[i] = a[i - 1] ^ a[i];
}
x = sqrt(n);
for (int i = 0; i < m; ++i) {
q[i].id = i;
pos[i] = i / x;
scanf("%d%d", &q[i].L, &q[i].R);
q[i].L--;
}
sort(q, q + m);
res = 0, curL = 0, curR = -1;
for (int i = 0; i < m; ++i) {
while (curL < q[i].L) del(curL++);
while (curL > q[i].L) add(--curL);
while (curR < q[i].R) add(++curR);
while (curR > q[i].R) del(curR--);
ans[q[i].id] = res;
}
for (int i = 0; i < m; ++i)
printf("%d\n", ans[i]);
return 0;
}