题意
给出
N
N
N堆石子,两人每次从中任意一堆取任意个石子,最后无法取的人失败。
有
M
M
M个形如
r
a
b
r\ a\ b
r a b的询问,表示从
l
∈
[
a
,
b
]
l \in [a,b]
l∈[a,b],这个区间内从第
r
r
r堆石头开始取,取的最多的石头使得先手必胜,如果能取就取走。
思路
这显然是一个 N I M NIM NIM博弈,先手必胜当且仅当 A 1 x o r A 2 x o r . . . x o r A n ≠ 0 A_1\ xor\ A_2\ xor\ ...\ xor\ A_n\neq 0 A1 xor A2 xor ... xor An̸=0。
在
[
l
,
r
]
[l,r]
[l,r]中,我们设
x
x
x为
A
1
x
o
r
A
2
x
o
r
.
.
.
x
o
r
A
n
−
1
A_1\ xor\ A_2\ xor\ ...\ xor\ A_{n-1}
A1 xor A2 xor ... xor An−1,
k
k
k为
A
1
x
o
r
A
2
x
o
r
.
.
.
x
o
r
A
n
A_1\ xor\ A_2\ xor\ ...\ xor\ A_n
A1 xor A2 xor ... xor An,
那么对于当前局面,为了使
A
1
x
o
r
A
2
x
o
r
.
.
.
x
o
r
A
n
=
0
A_1\ xor\ A_2\ xor\ ...\ xor\ A_n = 0
A1 xor A2 xor ... xor An=0,我们可以使
A
r
A_r
Ar变成
A
r
x
o
r
k
=
x
A_r\ xor\ k=x
Ar xor k=x,因为
A
r
x
o
r
x
=
k
、
A
r
x
o
r
k
=
x
A_r\ xor\ x=k、A_r\ xor\ k=x
Ar xor x=k、Ar xor k=x,所以
x
x
o
r
x
=
0
x\ xor\ x=0
x xor x=0。取出石子最多,那么就是
A
r
−
x
A_r-x
Ar−x最大,故
x
x
x最小,我们这就可以暴力来做。
还有一个点,题目说要取走,那我们就更新 A A A。
代码
#include<cstdio>
#include<algorithm>
int n, m, r, a, b, ans, x;
int st[100001];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &st[i]);
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
scanf("%d %d %d", &r, &a, &b);
x = 0;
ans = 1 << 29;
if (!st[r]) {
printf("-1\n");
continue;
}
if (b == r) {
printf("%d\n", st[r]);
st[r] = 0;
continue;
}
for (int j = r - 1; j >= a; j--) {
x ^= st[j];
if (j <= b) ans = std::min(ans, x);
}
if (ans >= st[r]) printf("-1\n");
else {
printf("%d\n", st[r] - ans);
st[r] = ans;
}
}
}