Link
ybtoj 【博弈论课堂过关】【例题1】取火柴游戏
luogu P1247 取火柴游戏
luogu P2197 【模板】nim 游戏
题面//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了
题目大意
有 n 个火柴堆,第 i 堆火柴堆有 a[i] 根火柴
你和人机轮流取火柴
- 每次只能取一堆的火柴(不能跨堆取)
- 每次必须取,可以全部取完
拿走最后一根火柴的一方赢
解题思路
来来来,各位先食用一些论证
结论为,这种NIM游戏,先手赢,当且仅当
A
1
x
o
r
A
2
x
o
r
.
.
.
A
n
=
a
n
s
≠
0
A_1\ xor\ A_2\ xor...\ A_n\ =\ ans\ ≠ 0
A1 xor A2 xor... An = ans =0
那么方案怎么算呢??
当先手赢时,一定存在一个
A
a
n
s
w
x
o
r
a
n
s
<
A
a
n
s
w
A_{answ}\ xor\ ans\ <\ A_{answ}
Aansw xor ans < Aansw
这个
A
a
n
s
w
x
o
r
a
n
s
A_{answ}\ xor\ ans
Aansw xor ans就是第一步取完,剩下的火柴
那么
A
a
n
s
w
−
(
A
a
n
s
w
x
o
r
a
n
s
)
A_{answ}\ -\ (A_{answ}\ xor\ ans)
Aansw − (Aansw xor ans)就是第一步取的火柴
Code
#include <iostream>
#include <cstdio>
using namespace std;
int n, a[501000], ans;
int main() {
scanf("%d %d", &n, &a[1]);
ans = a[1];
for(int i = 2; i <= n; i ++) {
scanf("%d", &a[i]);
ans ^= a[i];
}
if(ans == 0) printf("Lose");
else {
for(int i = 1; i <= n; i ++)
if((a[i] ^ ans) < a[i]) {
printf("%d %d\n", a[i] - (a[i] ^ ans), i);
for(int j = 1; j < i; j ++)
printf("%d ", a[j]);
printf("%d ", a[i] ^ ans);
for(int j = i + 1; j <= n; j ++)
printf("%d ", a[j]);
break;
}
}
}