题目
CF617E XOR and Favorite Number
思路
莫队。
异或的性质:
1.(a oplus a = 0)
2.(a oplus 0 = a)
3.(a oplus b = k Rightarrow a oplus k = b)
我们处理出原序列的前缀异或数组 (sxor)。
如果 ([l,r]) 这个区间的异或为 (k) 那么 (sxor[r] oplus sxor[l - 1] = k)。(因为是 (l-1) 所以每个询问的左端点要左移)。
根据第三条性质,如果加入或删除某一个数 (x) 就变成了求 (x oplus k) 的数量。
注意数组开大点。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 100001
typedef long long ll;
ll now, ans[M];
int n, m, k, sqrn, cnt[M * 20], num[M], sxor[M];
struct query {
int x, y, id;
friend bool operator < (query q1, query q2) {
if (num[q1.x] == num[q2.x]) return q1.y < q2.y;
return num[q1.x] < num[q2.x];
}
}q[M];
void add(int x) {
now += cnt[x ^ k];
++cnt[x];
}
void del(int x) {
--cnt[x];
now -= cnt[x ^ k];
}
int main() {
scanf("%d %d %d", &n, &m, &k), sqrn = sqrt(n);
for (int i = 1, x; i <= n; ++i) {
scanf("%d", &x);
sxor[i] = sxor[i - 1] ^ x;
num[i] = (i - 1) / sqrn + 1;
}
for (int i = 1; i <= m; ++i) {
scanf("%d %d", &q[i].x, &q[i].y);
--q[i].x, q[i].id = i;
}
std::sort(q + 1, q + m + 1);
int l = 0, r = 0; cnt[0] = 1;
for (int i = 1; i <= m; ++i) {
while (l > q[i].x) add(sxor[--l]);
while (r < q[i].y) add(sxor[++r]);
while (l < q[i].x) del(sxor[l++]);
while (r > q[i].y) del(sxor[r--]);
ans[q[i].id] = now;
}
for (int i = 1; i <= m; ++i) printf("%lld
", ans[i]);
return 0;
}