取石子(五)
-
描述
-
himdd最近很想玩游戏,于是他找到acmj和他一起玩,游戏是这样的:有一堆石子,两个人轮流从其中取走一定的石子,取走最后所有石子的人为赢家,不过得遵循如下规则:
1.第一次取不能取完,至少取1颗.
2.从第二次开始,每个人取的石子数至少为1,至多为对手刚取的石子数的两倍。
himdd事先想知道自己会不会赢,你能帮帮他吗?(每次himdd先手)
-
输入
-
有多组测试数据,每组有一个整数n(2<=n<2^64);
输出
- himdd会赢输出Yes,否则输出No; 样例输入
-
2 5 6
样例输出
-
No No Yes
思路:
结论:当n为fibonacci数时,先手必败(n >= 2);
-
证明:
-
以下为个人思路:
-
根据“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和(优先选取最大的)。
-
比如 n = 14 时, n = 8 + 5 + 1;而先手要赢的条件是,先手必须要先取完最小的一堆,再取完次小的一堆,以此类推,并保证每堆的最后一个是自己取到的而且不能取超!听起来有点绕,举个例子:
-
1、先看必胜态,n不是fibonacci数的时候,令n = 9 =5 + 3 + 1:
-
a、先手先取最小的一堆,1个,保证了最后一个是自己取得;
-
b、此时后手开始取次小的一堆(3个石子),上面说过,要想赢的话,要保证这一堆的第3个必须是自己取得;此时后手有 1个、2个两种取法,但此处无论后手怎么取,都能保证这一堆的最后一个(第3个)是自己取得;
-
c、此时后手开始取最后一堆(5个石子),b步先手可能取得是1或2,因此此步后手可能有1、2、3、4四种取法,易知后手取3或4的话,自己立马就能取到最后一个,就赢了,而取1或2时,同上(读者自己来),仍能保证取到最后一个(此堆第5个,全局最后一个),必赢!
-
2、再说必败态,若n本身是fibonacci数时,已经不需要分解了,为方便观察,令n=5:
-
实际上与上面相同,每一堆(有fib个石子)在自己先手的情况下,无论怎么取,后手都能保证自己取到这一堆的最后一个,因此后手必胜!
-
PS:所以上面说总石子数为非fibonacci数时先手必胜的原因在于,总数目分解为若干fib数时,先手先全部取走最小的一堆1个(也是取到了这一堆的最后一个),以后每堆(有fib[i]个石子)都是后手先取,先手便有把握取到这一堆的最后一个了!
-
-
代码:
-
#include <stdio.h> #define N 100 long long fib[N]; void Fib() { fib[0] = 0; fib[1] = 1; for(int i = 2; i < N; i ++){ fib[i] = fib[i - 1] + fib[i - 2]; } } int main() { Fib(); long long n; while(scanf("%lld", &n) != EOF){ bool is_fib = 0; for(int i = 2; i < 100; i ++){ if(fib[i] == n){ is_fib = 1; break; } } if(is_fib) printf("No\n"); else printf("Yes\n"); } return 0; }
-
-
-
-
-
-
-
有多组测试数据,每组有一个整数n(2<=n<2^64);