HDU1848 Fibonacci again and again(SG 函数)

任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: 
F(1)=1; 
F(2)=2; 
F(n)=F(n-1)+F(n-2)(n>=3); 
所以,1,2,3,5,8,13……就是菲波那契数列。 
在HDOJ上有不少相关的题目,比如1005 Fibonacci again就是曾经的浙江省赛题。 
今天,又一个关于Fibonacci的题目出现了,它是一个小游戏,定义如下: 
1、  这是一个二人游戏; 
2、  一共有3堆石子,数量分别是m, n, p个; 
3、  两人轮流走; 
4、  每走一步可以选择任意一堆石子,然后取走f个; 
5、  f只能是菲波那契数列中的元素(即每次只能取1,2,3,5,8…等数量); 
6、  最先取光所有石子的人为胜者; 

假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。 

Input输入数据包含多个测试用例,每个测试用例占一行,包含3个整数m,n,p(1<=m,n,p<=1000)。 
m=n=p=0则表示输入结束。 
Output如果先手的人能赢,请输出“Fibo”,否则请输出“Nacci”,每个实例的输出占一行。 
Sample Input

1 1 1
1 4 1
0 0 0

Sample Output

Fibo
Nacci
题解:假的斐波那契博弈;用SG函数推导,只要前20个斐波那契数即可;
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e4+10; 
 4 int m,n,p;
 5 int fibo[30];
 6 int SG[maxn],vis[maxn];
 7 void GetSG(int x)
 8 {
 9     memset(SG,0,sizeof SG);
10     int t=1;
11     for(int i=1;i<=x;++i)
12     {
13         for(int j=0;j<30&&fibo[j]<=i;++j) vis[SG[i-fibo[j]]]=t;
14         for(int j=0;j<=x;++j){if(vis[j]!=t){SG[i]=j;break;}}
15         ++t;
16     }
17 }
18 int main()
19 {
20     fibo[0]=1,fibo[1]=2;
21     for(int i=2;i<30;++i) fibo[i]=fibo[i-1]+fibo[i-2]; 
22     GetSG(maxn-5);
23     while(~scanf("%d%d%d",&m,&n,&p))
24     {
25         if(!m&&!n&&!p) break;
26         int ans=SG[m]^SG[n]^SG[p];
27         if(ans) puts("Fibo");
28         else puts("Nacci");    
29     }
30     
31     return 0;
32 }
View Code
原文地址:https://www.cnblogs.com/csushl/p/10331535.html