sg函数打表
//f[]:可以取走的石子个数 //sg[]:0~n的SG函数值 //hash[]:mex{} int f[N],sg[N],hash[N]; void getSG(int n) { int i,j; memset(sg,0,sizeof(sg)); for(i=1;i<=n;i++) { memset(hash,0,sizeof(hash)); for(j=1;f[j]<=i;j++) hash[sg[i-f[j]]]=1; for(j=0;j<=n;j++) //求mes{}中未出现的最小的非负整数 { if(hash[j]==0) { sg[i]=j; break; } } } }dfs
//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍 //n是集合s的大小 S[i]是定义的特殊取法规则的数组 int s[110],sg[10010],n; int SG_dfs(int x) { int i; if(sg[x]!=-1) return sg[x]; bool vis[110]; memset(vis,0,sizeof(vis)); for(i=0;i<n;i++) { if(x>=s[i]) { SG_dfs(x-s[i]); vis[sg[x-s[i]]]=1; } } int e; for(i=0;;i++) if(!vis[i]) { e=i; break; } return sg[x]=e; }
分别把每一堆的SG函数计算出来,就可以利用组合游戏的结论进行Nim异或了
第一堆求出SG函数可以发现有规律0,1,2,0,1,2……循环
第二堆无规律求出sg2[]
第三堆sg[a]=a;
第四堆无规律求出sg4[]
第五堆规律0,1,0,1,0,1……
第六堆及其以后根据巴什博弈,sg[a]=a%(i+1);
#include<stdio.h> #include<string.h> int f[25],sg2[1005],vis[1005]; int ff[1000],sg4[1005]; void fib()//斐波那契数 { f[1]=1; f[2]=2; for(int i=3; i<=20; i++) f[i]=f[i-1]+f[i-2]; return ; } void get_ff()//1和偶数 { ff[1]=1; for(int i=1; i<=500; i++) { ff[i+1]=2*i; } } int get_sg2(int n)//第二堆sg { fib(); memset(sg2,0,sizeof(sg2)); for(int i=1; i<=n; i++) { memset(vis,0,sizeof(vis)); for(int j=1; f[j]<=i; j++) vis[sg2[i-f[j]]]=1; for(int j=0; j<=n; j++) if(vis[j]==0) { sg2[i]=j; break; } } return sg2[n]; } int get_sg4(int n)//第四堆sg { memset(sg4,0,sizeof(sg4)); get_ff(); for(int i=1; i<=n; i++) { memset(vis,0,sizeof(vis)); for(int j=1; ff[j]<=i; j++) vis[sg4[i-ff[j]]]=1; for(int j=0; j<=n; j++) if(vis[j]==0) { sg4[i]=j; break; } } return sg4[n]; } int main() { int m,n,p,a; while(~scanf("%d",&n)&&n) { int f=0; for(int i=1; i<=n; i++) { scanf("%d",&a); if(i==1) { f^=(a%3); } else if(i==2) { f^=get_sg2(a); } else if(i==3) { f^=a; } else if(i==4) { f^=get_sg4(a); } else if(i==5) { f^=(a%2); } else { f^=(a%(i+1)); } } if(f>0) { printf("Yougth\n"); } else { printf("Hrdv\n"); } } }