HDU 1848 Fibonacci again and again(博弈_SG函数)

来源:互联网 发布:武汉育才行知小学校歌 编辑:程序博客网 时间:2024/05/21 04:43

【题目链接】
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;}
0 0