母题:有一堆个数为n的石子,游戏双方轮流取石子,满足:
1)先手不能在第一次把所有的石子取完;
2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。
这种博弈题麻烦的地方是每次走的步数限制是动态的,是根据上一步对手走的步数来推断,这里必须要引入一个定理:齐肯多夫定理
任何正整数都可以表示成若干个不连续的斐波那契数之和。这种和式称为齐肯多夫表述法。
也就是说,每个数都能有不连续的斐波那契数来表示。
我们以83为例:83被夹在55和89之间,所以83=55+28,28被夹在21和34之间,28=21+7,7=5+2。这样分解的意义是,假设先手先取走2,那么后手最多取走1~4,假设他取走4,那么你就能取走1。然后他取走2,你取走4,他取走8,你取走7。总之,进过几轮,你都能取走剩下的数,使之保持为一个斐波那契数。所以先手一定赢
我们再以89为例:89=55+34,假如先取的数大于等于34,那么剩下的55<34*2,所以后手胜,假如说取的数y< = 34,那么剩下的数x在55到89之间,x=55+a1+a2+..+an,当an < =2y时,根据之前的分析,就能获得先手胜的局面
例:取石子游戏(hud 2516)
Problem Description
1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出”Second win”.先取者胜输出”First win”.
Input
输入有多组.每组第1行是2<=n<2^31. n=0退出.
Output
先取者负输出”Second win”. 先取者胜输出”First win”.
参看Sample Output.
Sample Input
2
13
10000
0
Sample Output
Second win
Second win
First win
因为没有规定先手第一次取多少,所以不用判断n为斐波那契数时的先手胜的情况
AC代码:
#include<bits/stdc++.h>
using namespace std;
using LL =int64_t;
LL fib[55] ;
void init() {
fib[1]=1,fib[2]=1;
for(int i=3;i<=50;i++) fib[i]=fib[i-1]+fib[i-2];
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
LL n;
init();
while(cin>>n&&n) {
for(int i=1;i<=50;i++) {
if(fib[i]==n) {
cout<<"Second win"<<endl;
break;
}
else if(fib[i]>n) {
cout<<"First win"<<endl;
break;
}
}
}
return 0;
}