【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=1848
【解题报告】
一堆石子的问题可以直接维护sg函数。求出G[n]的sg值(我的理解是,把n-1,n-2,n-3,n-5…这些状态通过sg值转换为n-1,n-2,n-3,n-4…这些状态,即不连续的拿取状态映射为连续的拿取状态,这样就可以把这道题目转化为像HDU1849这样的典型nim问题来求解)
三堆石子那么SG( n,m,p )=SG[n]^SG[m]^SG[p]
(和解决nim问题是类似的)
SG=0那么是个P状态(必败)
SG=1那么是个N状态(必胜)
求SG值的时间复杂度为O(n^2).在本题小数据范围内可解。有时间研究下存不存在O(nlogn)的解法。
【参考资料】
《SG函数资料》–冰刃逆袭丿
http://blog.sina.com.cn/s/blog_83d1d5c70100y9yd.html
【参考代码】
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1000;
int sg[maxn+50],fib[20];
int cnt;
void init()
{
memset(fib,0,sizeof(fib));
memset(sg,0,sizeof(sg));
fib[0]=1;fib[1]=1;
cnt=1;
while(fib[cnt]<=1000)
{
fib[++cnt]=fib[cnt-1]+fib[cnt-2];
}
for( int i=1; i<=maxn; i++ )
{
int tag[1000];
memset(tag,0,sizeof(tag));
for( int j=1; j<=cnt; j++ )
{
if(fib[j]>i)break;
tag[ sg[i-fib[j]] ]=1; //i可以达到i-fib[j]这个状态,即可以到达对应的sg值
}
int j=0;
while(tag[j])j++;
sg[i]=j;
}
}
int main()
{
init();
int m,n,p;
while(~scanf("%d%d%d",&m,&n,&p) && (m+n+p) )
{
int state=0;
state=state^sg[m]^sg[n]^sg[p];
if(state)printf("Fibo\n");
else printf("Nacci\n");
}
return 0;
}