题目:http://acm.hdu.edu.cn/showproblem.php?pid=1848
题意:有3堆石子,石子数量分别为a,b,c,有两个玩家,每次只能从任意一堆中取f个,这里的f只能为fibnacci数,问是先手胜
还是先手败.
分析:由于石子的数量都在1000以内,那么我们可以先预处理出1000以内的SG函数值,然后对于3堆石子,我们进行异或,如果为
0说明先手必败,否则必胜,当然求SG函数的值用深搜就行了.
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int N = 1005; const int M = 25; int fib[25]; int SG[N]; int mex(int x) { bool vis[M]; memset(vis,0,sizeof(vis)); for(int i=0;i<M;i++) { int t = x - fib[i]; if(t < 0) break; if(SG[t] == -1) SG[t] = mex(t); vis[SG[t]] = 1; } for(int i=0;;i++) if(!vis[i]) return i; } void Init() { fib[0] = 1; fib[1] = 2; for(int i=2;i<M;i++) fib[i] = fib[i-1] + fib[i-2]; memset(SG,-1,sizeof(SG)); for(int i=0;i<N;i++) SG[i] = mex(i); } int main() { Init(); int a,b,c; while(~scanf("%d%d%d",&a,&b,&c)) { if(a == 0 && b == 0 && c == 0) break; int ans = 0; ans ^= SG[a]; ans ^= SG[b]; ans ^= SG[c]; if(ans) puts("Fibo"); else puts("Nacci"); } return 0; }
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1536
分析:本题基本上跟上体一样,只是把3堆改为x堆,把取fibnacci数列颗石子改为取指定输入的石子个数.那么做法实际上一
样,我们对输入的序列进行排序,然后求出它们的SG函数的值,然后直接用即可.
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> using namespace std; const int N = 10005; const int M = 105; int a[M]; int SG[N]; int n; int mex(int x) { bool vis[M]; memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++) { int t = x - a[i]; if(t < 0) break; if(SG[t] == -1) SG[t] = mex(t); vis[SG[t]] = 1; } for(int i=0;;i++) if(!vis[i]) return i; } int main() { while(~scanf("%d",&n)) { if(n == 0) break; for(int i=0;i<n;i++) scanf("%d",&a[i]); sort(a,a+n); memset(SG,-1,sizeof(SG)); for(int i=0;i<N;i++) SG[i] = mex(i); int m; scanf("%d",&m); while(m--) { int ans = 0; int len,t; scanf("%d",&len); for(int i=0;i<len;i++) { scanf("%d",&t); ans ^= SG[t]; } if(ans) printf("W"); else printf("L"); } puts(""); } return 0; }