给定一个长度为
N
N
N的数组,一个整数
K
K
K,求区间
l
∼
r
l \sim r
l∼r中有多少
p
a
i
r
{
i
,
j
}
,
i
<
=
j
pair\{i,j\},i<=j
pair{i,j},i<=j,满足
a
i
⊕
a
i
+
1
⊕
.
.
.
⊕
a
j
=
K
a_i \oplus a_{i+1} \oplus ... \oplus a_j=K
ai⊕ai+1⊕...⊕aj=K
传送门
分析
先考虑暴力
求
a
i
⊕
a
i
+
1
⊕
.
.
.
⊕
a
j
a_i \oplus a_{i+1} \oplus ... \oplus a_j
ai⊕ai+1⊕...⊕aj 就是要求,异或前缀下的
o
s
u
m
i
−
1
⊕
o
s
u
m
j
osum_{i-1} \oplus osum_j
osumi−1⊕osumj
固定起点
l
l
l,暴力往后走
假如走到
i
i
i的位置,计算
o
s
u
m
l
−
1
⊕
o
s
u
m
i
osum_{l-1} \oplus osum_i
osuml−1⊕osumi,如果等于
K
K
K的话就加
1
1
1,依次计算,复杂度
M
∗
N
2
M*N^2
M∗N2
再想想优化
上面复杂度显然不行,考虑固定左端点,拓展右端点的时候直接把所有以右端点结尾的答案都计算出来
如果当前右端点走到了
i
i
i位置,因为我们要找到异或后等于
K
K
K的值,既然要让
i
i
i能做出贡献,那么此时一定在前面计算的某一个左端点
j
j
j,存在
o
s
u
m
j
−
1
⊕
o
s
u
m
i
=
K
osum_{j-1} \oplus osum_i = K
osumj−1⊕osumi=K,推出
o
s
u
m
j
−
1
=
o
s
u
m
i
⊕
K
osum_{j-1} = osum_i \oplus K
osumj−1=osumi⊕K,也就是说,所有以
i
i
i为结尾的区间异或等于
K
K
K的贡献,就是前面计算的所有,值等于
o
s
u
m
i
⊕
K
osum_i \oplus K
osumi⊕K的数量
考虑添加一个数
x
x
x,计数器
c
n
t
[
x
⊕
K
]
+
+
cnt[x \oplus K]++
cnt[x⊕K]++,答案
a
n
s
+
=
c
n
t
[
x
⊕
K
]
ans+=cnt[x \oplus K]
ans+=cnt[x⊕K]
考虑删除一个数
x
x
x,计数器
c
n
t
[
x
⊕
K
]
−
−
cnt[x \oplus K]--
cnt[x⊕K]−−,答案
a
n
s
−
=
c
n
t
[
x
⊕
K
]
ans -= cnt[x \oplus K]
ans−=cnt[x⊕K]
注意细节,题目要求是 i = = j i==j i==j是合法的,所以得先计数器改变,再统计答案个数
那么计算一个区间内满足条件的个数,时间复杂度就是 N N N了
接下来就是,如何求出多个区间的问题?
普通莫队就能够解决
添加,删除的操作上面应该已经说清楚了
代码
//CF617
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
int arr[MAX_N];
int cnt[MAX_N<<1];
int mo = 0;
int ans[MAX_N];
void add(int x) {
mo += cnt[arr[x]^K];
++cnt[arr[x]];
}
void del(int x) {
--cnt[arr[x]];
mo -= cnt[arr[x]^K];
}
int block;
int idb(int x) {
return x/block;
}
struct Qr {
int l, r, id;
bool operator < (const Qr& B) const {
return idb(l) ^ idb(B.l)? l < B.l : (idb(l)&1) ? r < B.r : r > B.r;
}
}qr[MAX_N];
void solve(){
sc("%lld%lld%lld", &N, &M, &K);
block = max(sqrt(N), sqrt((N*N)/M));
for (int i = 1; i <= N; ++i) {
sc("%lld", &arr[i]);
arr[i] ^= arr[i-1];
}
for (int i = 1; i <= M; ++i) {
sc("%lld%lld", &qr[i].l, &qr[i].r);
--qr[i].l;
qr[i].id = i;
}
sort(qr+1, qr+1+M);
int l = 1, r = 0;
mo = 0;
for (int i = 1; i <= M; ++i) {
while (l > qr[i].l) add(--l);
while (r < qr[i].r) add(++r);
while (l < qr[i].l) del(l++);
while (r > qr[i].r) del(r--);
ans[qr[i].id] = mo;
}
for (int i = 1; i <= M; ++i) {
pr("%lld\n", ans[i]);
}
}
signed main()
{
#ifndef ONLINE_JUDGE
//FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}