大致题意: 有(n)个石头,每次取的石头数量不能超过另一个人前次取的石头数量的两倍,取到最后一个石头赢。问先手第一次至少取多少石头,才能保证必胜。
前言
稀奇古怪的博弈论题。。。
说实话我并不知道斐波那契博弈除了这道板子题以外还能干什么。。。
斐波那契博弈
对于这道题,有这样一个结论:对于一个斐波那契数,先手必须一次取完,否则必输。
考虑用归纳思想证明。
对于(Fib_1=1)和(Fib_2=2)的情况,这个结论显然成立。
否则对于第(i)个斐波那契数(Fib_i=Fib_{i-2}+Fib_{i-1}),假设我们已经证明这一结论对于(Fib_{i-2})和(Fib_{i-1})成立。
而斐波那契数满足性质(2Fib_xge Fib_{i+1}),所以如果先手不一次取完,且取的石头数(ge Fib_{i-2}),显然后手可以一次取完。
因此先手不能一次取完(Fib_{i-2})。而我们把(Fib_{i-2})和(Fib_{i-1})分别看作两堆石头,则根据对(Fib_{i-2})已经证明的这一结论,后手必然可以取到(Fib_{i-2})这堆中的最后一个石头。
考虑后手最后一次取最多也只能是取(frac23 imes Fib_{i-2})个石头(即先手一次取走(frac13 imes Fib_{i-2})个石头),而(frac 43 imes Fib_{i-2})显然是小于(Fib_{i-1})的。
这也就意味着先手不能一次取完(Fib_{i-1})这一堆,而根据对(Fib_{i-1})已经证明的这一结论,后手可以取到(Fib_{i-1})这一堆的最后一个石头,也就是(Fib_i)中的最后一个石头。
于是这个结论就得证了。
而我们考虑一个非斐波那契数,我们可以把它分解成若干个非连续的斐波那契数(因为连续的斐波那契数(Fib_{i-2},Fib_{i-1})可以拼成(Fib_i))的和。
此时先手怎样才能赢呢?
由于斐波那契数的性质(2Fib_x<Fib_{x+2}),对于这些非连续的斐波那契数,一次取完较小的一堆后,另一个人无法一次取完较大的一堆。
所以,先手只要取走最小的斐波那契数,就能让自己成为后手,然后从小到大依次取完每一堆,就必胜了。
而具体代码实现是非常简单的。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LL long long
using namespace std;
LL n,Fib[60];
int main()
{
RI i;for(scanf("%lld",&n),Fib[1]=1,Fib[2]=2,i=3;(Fib[i]=Fib[i-2]+Fib[i-1])<n;++i);//求斐波那契数
W(n^Fib[i]) n>Fib[i]&&(n-=Fib[i]),--i;return printf("%d",n),0;//斐波那契分解,答案是最小的斐波那契数
}