题意:
给定
n
n
n个石子堆,每堆有
a
i
a_i
ai个石子(
a
i
>
0
a_i>0
ai>0),每次可以选择一堆石子,从这堆石子中选择任意多的石子。两者皆采取最优策略,问什么状态下先手必败,什么状态下先手必胜。
题解:
经典尼姆游戏。
当
a
1
⊕
a
2
⊕
a
3
⊕
.
.
.
⊕
a
n
−
1
⊕
a
n
=
0
a_1\oplus a_2\oplus a_3\oplus ...\oplus a_{n-1}\oplus a_n=0
a1⊕a2⊕a3⊕...⊕an−1⊕an=0,先手必败。
当
a
1
⊕
a
2
⊕
a
3
⊕
.
.
.
⊕
a
n
−
1
⊕
a
n
≠
0
a_1\oplus a_2\oplus a_3\oplus ...\oplus a_{n-1}\oplus a_n\neq 0
a1⊕a2⊕a3⊕...⊕an−1⊕an=0,先手必胜。
证明:定义
s
u
m
=
a
1
⊕
a
2
⊕
a
3
⊕
.
.
.
⊕
a
n
−
1
⊕
a
n
sum=a_1\oplus a_2\oplus a_3\oplus ...\oplus a_{n-1}\oplus a_n
sum=a1⊕a2⊕a3⊕...⊕an−1⊕an。
终态一定是所有石子堆的石子个数都为
0
0
0,即
s
u
m
=
0
sum=0
sum=0时。
这里推测:
- s u m = 0 sum=0 sum=0时,先手必败
- s u m ≠ 0 sum\neq 0 sum=0时,先手必胜
证明:
考虑先手处于必胜态时,此时
s
u
m
≠
0
sum\neq 0
sum=0,那么先手必然要拿掉一些石子使得后手面临必败态,即先手拿掉一些石子后使得
s
u
m
=
0
sum=0
sum=0。
这里令被操作的石子堆是第
i
i
i堆,操作前的剩余
n
−
1
n-1
n−1堆石子异或值为
H
=
s
u
m
⊕
a
i
H=sum\oplus a_i
H=sum⊕ai,若将第
i
i
i堆石子数量降至
H
H
H,则
H
⊕
H
=
0
H\oplus H=0
H⊕H=0,此时后手将面临必败态。
问题转化为了寻找一个
a
i
a_i
ai,使得
a
i
>
H
a_i>H
ai>H。
这里对于
s
u
m
sum
sum的二进制最高位
k
k
k,必然也是一个数
a
i
a_i
ai的二进制最高位,那么选择该
a
i
a_i
ai,
H
H
H必然比
a
i
a_i
ai小,因此必然存在这样一个数使得
a
i
>
H
a_i>H
ai>H。
证毕。
以上是对于经典尼姆游戏的证明。
那么若限制每次拿石子的个数为指定集合中的任意一个数,如何解决判断必败态和必胜态。
考虑 S G SG SG函数的构造。(具体的 S G SG SG函数介绍省略。)
直接给出结论:
令
s
u
m
=
S
G
(
a
1
)
⊕
S
G
(
a
2
)
⊕
S
G
(
a
3
)
⊕
.
.
.
⊕
S
G
(
a
n
−
1
)
⊕
S
G
(
a
n
)
sum=SG(a_1)\oplus SG(a_2)\oplus SG(a_3)\oplus ...\oplus SG(a_{n-1})\oplus SG(a_n)
sum=SG(a1)⊕SG(a2)⊕SG(a3)⊕...⊕SG(an−1)⊕SG(an)
这里仍然推测:
- s u m = 0 sum=0 sum=0时,先手必败
- s u m ≠ 0 sum\neq 0 sum=0时,先手必胜
考虑到 S G SG SG函数的定义, S G ( a i ) SG(a_i) SG(ai)可以到达任意小于 S G ( a i ) SG(a_i) SG(ai),即上一个模型,证明与尼姆游戏的普通版本一样。问题转化为了如何求解 S G SG SG函数。
给出一个以 f i b fib fib数列作为可取石子的个数集合的 S G SG SG函数的模板: h d u 1848. hdu1848. hdu1848.
int fib[17] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987};
int sg(int x) {
if(~f[x]) return f[x];
bool jud[M]; //M指的是需要的最大sg参数
memset(jud, false, sizeof jud);
for(int i = 1; i <= 15 && x >= fib[i]; ++i) jud[sg(x - fib[i])] = true;
for(int i = 0; ; ++i) if(!jud[i]) return f[x] = i;
}