hdu 3032 Nim or not Nim? 博弈(SG定理+找规律)

来源:互联网 发布:单片机串口初始化 编辑:程序博客网 时间:2024/05/12 01:47

题意:给定n堆石子,两人轮流操作,每次选一堆石子,取任意石子或则将石子分成两个更小的堆(非0),取得最后一个石子的为胜。

题解:比较裸的SG定理,用sg定理打表,得到表1,2,4,3,5,6,8,7,9,10,12,11...可以发现当x%4==0时sg[x]=x-1;当x%4==3时sg[x]=x+1;其余sg[x]=x。然后异或下就出来结果了。主要还是用学会SG定理。详细的可以百度,或则看我其他的文章(我自己都忘了哪篇写过。。大笑)



#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn=1e6+10;int find(int x){    if(x%4==0)return x-1;    else if(x%4==3)return x+1;    return x;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        int a,n,i,j,ans=0;        scanf("%d",&n);        for(i=0;i<n;i++)        {            scanf("%d",&a);            ans=ans^find(a);        }        if(ans==0)printf("Bob\n");        else printf("Alice\n");    }    return 0;}


SG定理打表+找规律:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn=1e4+10;int sg[maxn],vis[maxn];void init(){    int i,j,k;    sg[0]=0,sg[1]=1;    for(i=2;i<=1000;i++)    {        memset(vis,0,sizeof(vis));        for(j=1;j<i;j++)        vis[sg[j]^sg[i-j]]=1;  //拆分        for(j=0;j<i;j++)        vis[sg[j]]=1;         //取石子        for(j=0;;j++)        if(!vis[j])break;        sg[i]=j;    }    for(i=1;i<=20;i++)    cout<<sg[i]<<endl;}int main(){    init();}