先从NIM游戏说起
有
n
n
n堆石子,第
i
i
i堆石子的个数为
a
i
a_i
ai
每个人每次只能从一堆种取若干个石子,最后不能取的人输,两个人都绝顶聪明,问先手必胜还是必败
结论是这样的:
如果
a
1
⊕
a
2
⊕
.
.
.
⊕
a
n
=
0
a_1\oplus a_2\oplus ...\oplus a_n=0
a1⊕a2⊕...⊕an=0,那么先手必败,否则先手必胜
为了便于叙述,我把
a
1
⊕
a
2
⊕
.
.
.
⊕
a
n
=
0
a_1\oplus a_2\oplus ...\oplus a_n=0
a1⊕a2⊕...⊕an=0叫做
a
1
.
.
.
a
n
a_1...a_n
a1...an这
n
n
n个数字的
n
i
m
nim
nim和(异或和)
证明可以用数学归纳法:
基础
如果每堆石子的个数都是 0 0 0,那么先手已经无法操作,此时先手必败
归纳
假设当前总石子数为 S S S总石子数为 k < S k<S k<S时该结论成立
- 当 n i m nim nim和等于 0 0 0时,假设我取第 i i i堆里的石子,显然 a i > 0 a_i>0 ai>0,因为 a i a_i ai与其它石子堆的 n i m nim nim和为 0 0 0,所以其它石子堆的 n i m nim nim和就等于 a i a_i ai,不管我在 a i a_i ai中取几个石子,取完之后这一堆里面剩下的石子数 a i ′ ̸ = a i a_i'\not = a_i ai′̸=ai,那么总的 n i m nim nim和也就不再等于 0 0 0,根据假设,这时我处于必胜态,也就是说最开始的状态就是先手必败态。
- 当 n i m nim nim和不等于 0 0 0时,假设 n i m nim nim和为 k k k,考虑 k k k二进制最高位上的 1 1 1,肯定有至少一堆石子的这一位也是 1 1 1,就随便取其中一堆,不妨设它是第 i i i堆,设其余堆的 n i m nim nim和为 x x x,那么 a i ⊕ x = k a_i\oplus x=k ai⊕x=k。我把第 i i i堆取成 a i ⊕ k a_i\oplus k ai⊕k,那么最后的 n i m nim nim和就是 ( a i ⊕ k ) ⊕ x = 0 (a_i\oplus k) \oplus x = 0 (ai⊕k)⊕x=0,而 a i ⊕ k < a i a_i\oplus k < a_i ai⊕k<ai,也就是说着这种方案一定存在。根据假设,取完之后我面临先手必败局面,也就是说一开始我处于先手必胜态
结论
根据数学归纳法第二原理,若 n n n堆石子的异或和为 0 0 0则先手必败,否则先手必胜。
SG函数、SG定理
这一部分的具体原理目前还没看懂…具体请详见《由感性认识到理性认识——透析一类搏弈游戏的解答过程》
对于这样的游戏:
双方轮流操作,不能操作的输
双方的操作规则是相同的
无论怎样操作,游戏总能在有限步内完成
就是说对于每种局面
x
x
x,给一个函数值
S
G
(
x
)
SG(x)
SG(x),假设
x
x
x的后继局面为
x
1
,
x
2
,
x
3
.
.
.
x
k
x_1,x_2,x_3...x_k
x1,x2,x3...xk,那么
S
G
(
x
)
=
m
e
x
{
S
G
(
x
1
)
,
S
G
(
x
2
)
,
.
.
.
,
S
G
(
x
k
)
}
SG(x)=mex\{SG(x_1),SG(x_2),...,SG(x_k)\}
SG(x)=mex{SG(x1),SG(x2),...,SG(xk)},
m
e
x
(
A
)
mex(A)
mex(A)表示不存在在集合
A
A
A中的最小自然数(
A
A
A是自然数集的有限子集)。
若
S
G
(
x
)
=
0
SG(x)=0
SG(x)=0则局面
x
x
x为必败态,否则为必胜态
游戏的和:
如果一个游戏
G
G
G是由若干互不相干的游戏
g
a
m
e
1
,
g
a
m
e
2
,
.
.
.
,
g
a
m
e
k
game_1,game_2,...,game_k
game1,game2,...,gamek构成,玩家可以进入任何一个游戏并在这个游戏中操作一步,对于这种情况,
S
G
(
G
)
=
S
G
(
g
a
m
e
1
)
⊕
S
G
(
g
a
m
e
2
)
⊕
.
.
.
⊕
S
G
(
g
a
m
e
k
)
SG(G)=SG(game_1)\oplus SG(game_2)\oplus...\oplus SG(game_k)
SG(G)=SG(game1)⊕SG(game2)⊕...⊕SG(gamek)
UVA1378 - A Funny Stone Game
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4124
这题可以把一个石子看作一个游戏,
S
G
(
x
)
SG(x)
SG(x)表示第
x
x
x堆上的一个石子所构成的游戏,其后继局面就是第
j
j
j堆中的一个石子和第
k
k
k堆中的一个石子,而且这两个石子是互不相干的两个游戏,因此可以应用
S
G
SG
SG定理来解决,枚举
j
,
k
j,k
j,k,
S
G
(
i
)
=
m
e
x
i
<
j
≤
k
(
{
S
G
(
j
)
⊕
S
G
(
k
)
}
)
SG(i) = mex_{i<j\leq k}(\{SG(j)\oplus SG(k)\})
SG(i)=mexi<j≤k({SG(j)⊕SG(k)})
#include <bits/stdc++.h>
#define maxn 2019
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
ll SG[maxn], s[maxn], tmp[maxn], N;
ll read(ll x=0)
{
ll c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f*x;
}
ll mex()
{
ll i;
for(i=0;i<maxn;i++)
if(!tmp[i])return i;
}
bool judge()
{
cl(SG);
ll i, j, k, nim, x;
for(i=N-1;i;i--)
{
cl(tmp);
for(j=i+1;j<=N;j++)
for(k=j;k<=N;k++)
tmp[SG[j]^SG[k]] = 1;
SG[i] = mex();
}
nim = 0;
for(i=1;i<=N;i++)
{
nim ^= (~(s[i]&1)+1)&SG[i];
}
return !!nim;
}
int main()
{
ll i, j, k, kase=0, a, b, c;
while(N = read())
{
for(i=1;i<=N;i++)s[i] = read();
a = b = c = 0;
for(i=1;i<N and !a;i++)for(j=i+1;j<=N and !a;j++)for(k=j;k<=N and !a;k++)
{
if(s[i]>0)
{
s[i] --;
s[j] ++;
s[k] ++;
if(judge()==0)a=i, b=j, c=k;
s[i] ++;
s[j] --;
s[k] --;
}
}
kase++;
printf("Game %lld: %lld %lld %lld\n",kase,a-1,b-1,c-1);
}
return 0;
}