题意
给出NNN堆石子,两人每次从中任意一堆取任意个石子,最后无法取的人失败。
有MMM个形如r a br\ a\ br a b的询问,表示从l∈[a,b]l \in [a,b]l∈[a,b],这个区间内从第rrr堆石头开始取,取的最多的石头使得先手必胜,如果能取就取走。
思路
这显然是一个NIMNIMNIM博弈,先手必胜当且仅当A1 xor A2 xor ... xor An≠0A_1\ xor\ A_2\ xor\ ...\ xor\ A_n\neq 0A1 xor A2 xor ... xor An̸=0。
在[l,r][l,r][l,r]中,我们设xxx为A1 xor A2 xor ... xor An−1A_1\ xor\ A_2\ xor\ ...\ xor\ A_{n-1}A1 xor A2 xor ... xor An−1,kkk为A1 xor A2 xor ... xor AnA_1\ xor\ A_2\ xor\ ...\ xor\ A_nA1 xor A2 xor ... xor An,
那么对于当前局面,为了使A1 xor A2 xor ... xor An=0A_1\ xor\ A_2\ xor\ ...\ xor\ A_n = 0A1 xor A2 xor ... xor An=0,我们可以使ArA_rAr变成Ar xor k=xA_r\ xor\ k=xAr xor k=x,因为Ar xor x=k、Ar xor k=xA_r\ xor\ x=k、A_r\ xor\ k=xAr xor x=k、Ar xor k=x,所以x xor x=0x\ xor\ x=0x xor x=0。取出石子最多,那么就是Ar−xA_r-xAr−x最大,故xxx最小,我们这就可以暴力来做。
还有一个点,题目说要取走,那我们就更新AAA。
代码
#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;
}
}
}