题目
题意概要
有一堆石子,最开始有
n
n
n 颗。按照如下操作进行。
- 第一次操作,可以拿走任意颗,但不能拿完,也不能不拿。
- 以后的操作,拿走石子的数量不超过上一次的两倍。不能不拿。
- 拿走最后一颗石子的人将会获得胜利。
询问是否先手必胜。
数据范围与约定
1
<
n
<
2
31
1<n<2^{31}
1<n<231 ,以
n
=
0
n=0
n=0 作为多组数据结束的标识。
思路
有关斐波那契
斐波那契数列是大家所熟知的了, a 0 = a 1 = 1 ∀ n ∈ [ 0 , + ∞ ) , a n + 2 = a n + a n + 1 a_0=a_1=1\\\quad\\\forall n\in[0,+\infty),a_{n+2}=a_{n}+a_{n+1} a0=a1=1∀n∈[0,+∞),an+2=an+an+1
它有如下几个性质,想必是大家烂熟于心的了:
- ∀ n ∈ [ 0 , + ∞ ) , 2 a n ≥ a n + 1 \forall n\in[0,+\infty),2a_n\ge a_{n+1} ∀n∈[0,+∞),2an≥an+1 且等号仅在 n = 1 n=1 n=1 处成立。
- ∀ n ∈ [ 0 , + ∞ ) , 2 a n ≤ a n + 2 \forall n\in[0,+\infty),2a_n\le a_{n+2} ∀n∈[0,+∞),2an≤an+2 且等号仅在 n = 0 n=0 n=0 处成立。
为了叙述方便,把 ∃ n ∈ [ 0 , + ∞ ) , a n = x \exist n\in[0,+\infty),a_n=x ∃n∈[0,+∞),an=x 简称为“ x x x 是斐波那契数”。
齐肯多夫定理
试图用斐波那契数的和去表示一个正整数,结果如何?
重复如下步骤,直到 x = 0 x=0 x=0 为止。
- 找到一个最大的 t t t ,使得 a t ≤ x ∧ a t + 1 > x a_t\le x\wedge a_{t+1}>x at≤x∧at+1>x 。
- 将 a t a_t at 作为 x x x 的划分中的一部分。为了消除影响,将 x x x 减去 a t a_t at 。
毫无疑问,这种划分将在有限步内结束,并且和一定恰好为最初给定的 x x x 。
而且,这个划分 不存在两个相同的斐波那契数,也不会出现两个相邻的斐波那契数。
只需要注意到,第一步中满足 x < a t + 1 ⇔ x − a t < a t − 1 x<a_{t+1}\Leftrightarrow x-a_t<a_{t-1} x<at+1⇔x−at<at−1 即可。
必胜情况
假设 石子数 x x x 不是斐波那契数,那么先手必胜。
将其分解为斐波那契数求和,从小到大排序为 r 1 , r 2 , r 3 , … , r k ( k > 1 ) r_1,r_2,r_3,\dots,r_k(k>1) r1,r2,r3,…,rk(k>1) 。
先手第一次取走
r
1
r_1
r1 颗石子。不难发现,由于
r
1
,
r
2
r_1,r_2
r1,r2 不相邻,所以
2
r
1
<
r
2
2r_1<r_2
2r1<r2 (详见性质二
),于是
r
2
r_2
r2 是后手所不能取完的——这就变成了与原来的游戏相似的局面。倘若石子数为斐波那契数时,后手必胜,那么本次游戏的先手一定能够取走
r
2
r_2
r2 的最后一颗。类似地,先手会取走
r
3
,
…
,
r
k
r_3,\dots,r_k
r3,…,rk 的最后一颗,获得胜利。
必败情况
石子数是斐波那契数,则先手必败。
假设石子数为 a k a_k ak ,而第一次取走了 y y y 颗。
由于 a k = a k − 2 + a k − 1 a_k=a_{k-2}+a_{k-1} ak=ak−2+ak−1 且 2 a k − 2 ≥ a k − 1 2a_{k-2}\ge a_{k-1} 2ak−2≥ak−1 ,所以 y < a k − 2 y<a_{k-2} y<ak−2 (否则一招秒杀)。
那么将 a k − y a_{k}-y ak−y 进行斐波那契数分解,从大到小排列为 a k − 1 , a i , … , a j a_{k-1},a_{i},\dots,a_j ak−1,ai,…,aj 。
此时,如果
a
j
≤
2
y
a_j\le 2y
aj≤2y ,那么后手就可以利用上面的必胜情况
的策略,直接拿完
a
j
a_j
aj 取得胜利。
反证法,不妨设
a
j
>
2
y
a_j>2y
aj>2y ,那么
y
<
a
j
2
≤
a
j
−
1
y<\frac{a_j}{2}\le a_{j-1}
y<2aj≤aj−1 (详见性质一
)。
于是 a k = ( a k − y ) + y < ( a k − 1 + a i + ⋯ + a j ) + a j − 1 a_k=(a_{k}-y)+y<(a_{k-1}+a_i+\cdots+a_j)+a_{j-1} ak=(ak−y)+y<(ak−1+ai+⋯+aj)+aj−1
观察 a i + ⋯ + a j + a j − 1 a_i+\cdots+a_j+a_{j-1} ai+⋯+aj+aj−1 ,要知道, a i , … , a j a_i,\dots,a_j ai,…,aj 不相邻!
所以,我们给出上界 a i + ⋯ + a j + a j − 1 ≤ a i + 1 ≤ a k − 2 a_i+\dots+a_j+a_{j-1}\le a_{i+1}\le a_{k-2} ai+⋯+aj+aj−1≤ai+1≤ak−2 ( i i i 和 k − 1 k-1 k−1 也不相邻)。
然后有
a
k
<
a
k
−
1
+
a
k
−
2
=
a
k
a_k<a_{k-1}+a_{k-2}=a_k
ak<ak−1+ak−2=ak 。怎么可能?自己小于自己?他又不是nan
综上
其实直接的证明还不够严谨,因为必胜情况
和必败情况
是互相调用的。但是,放在
D
A
G
DAG
DAG 的博弈状态转移图里面,利用归纳法,就可以严谨的证明了。
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0' or c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c and c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline void writeint(long long x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) writeint(x/10);
putchar((x%10)^48);
}
# define MB template < class T >
MB void getMax(T &a,const T &b){ if(a < b) a = b; }
MB void getMin(T &a,const T &b){ if(b < a) a = b; }
set<int> s;
int main(){
long long a = 1, b = 1;
for(long long N=(1ll<<31); b<N; b+=a,a=b-a)
s.insert(int(b));
while(~scanf("%lld",&a))
if(a == 0) break;
else if(s.count(a)) puts("Second win");
else puts("First win");
return 0;
}