1. 程式人生 > >【HDU1848】Fibonacci again and again(博弈論)

【HDU1848】Fibonacci again and again(博弈論)

spa sync splay turn pro [1] 斐波那契 play cci

【HDU1848】Fibonacci again and again(博弈論)

題面

Hdu
你有三堆石子,每堆石子的個數是\(n,m,p\),你每次可以從一堆石子中取走斐波那契數列中一個元素等數量的石子數,兩人輪流取,不能操作者輸,判定先後手的勝利。

題解

根據\(SG\)定理,三堆石子可以拆開來看,最終狀態的\(SG\)函數為這三堆石子\(SG\)函數的異或值。
那麽,我們只需要預處理任意數量石子的\(SG\)值就好了。
對於一堆數量為\(x\)的石子的\(SG\)函數為:
\[SG(x)=mex\{SG(x-y),y\in Fib,x\ge y\}\]
直接預處理即可。

#include<iostream>
using namespace std;
int fib[20],n,m,p,SG[1010];
bool vis[1010];
int main()
{
    ios::sync_with_stdio(false);
    fib[1]=fib[2]=1;SG[0]=0;
    for(int i=3;i<=17;++i)fib[i]=fib[i-1]+fib[i-2];
    for(int i=1;i<=1000;++i)
    {
        for(int j=1;fib[j]<=i;++j)vis[SG[i-fib[j]]]=true;
        for(int j=0;;++j)if(!vis[j]){SG[i]=j;break;}
        for(int j=1;fib[j]<=i;++j)vis[SG[i-fib[j]]]=false;
    }
    while(233)
    {
        cin>>n>>m>>p;if(!n&&!m&&!p)break;
        if(SG[n]^SG[m]^SG[p])cout<<"Fibo"<<endl;
        else cout<<"Nacci"<<endl;
    }
    return 0;
}

【HDU1848】Fibonacci again and again(博弈論)