题目链接:http://poj.org/problem?id=2960
题目大意:给定数组S,接下来给出m个游戏局面。游戏局面是一些beads堆,先给出堆数,然后是每一堆中beads的数目。游戏规则是,两个人轮流取beads,每次可以选择一堆,从中取出k个beads,k ∈S,最后不能取的人输。
分析: 取每一堆石子都可以看成是一个单独的游戏,因此,n堆石子就是n个游戏,每个子游戏的状态是其beads的数目,胜负很好判定,求出sg函数即可。最后所有游戏局面的Nim和即为此题的解。
参考代码:(注意优化的那个地方)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 105 #define M 10005 int s[N], sn; int sg[M]; void getsg(int n) { int mk[M]; sg[0] = 0;//主要是让终止状态的sg为0 memset(mk, -1, sizeof(mk)); for(int i = 1; i < M; i++) { for(int j = 0; j < n && s[j] <= i; j++) mk[sg[i-s[j]]]=i;//将所有后继的sg标记为i,然后找到后继的sg没有出现过的最小正整数 //优化:注意这儿是标记成了i,刚开始标记成了1,这样每次需初始化mk,而标记成i就不需要了 int j = 0; while(mk[j] == i) j++; sg[i] = j; } } int main() { while(~scanf("%d", &sn), sn) { for(int i = 0; i < sn; i++) scanf("%d", &s[i]); sort(s, s+sn);//排序算一个优化,求sg的时候会用到 getsg(sn); int m; scanf("%d", &m); char ans[N]; for(int c = 0; c < m; c++) { int n, tm; scanf("%d", &n); int res = 0; for(int i = 0; i < n; i++) { scanf("%d", &tm); res ^= sg[tm]; } if(res == 0) ans[c] = 'L'; else ans[c] = 'W'; } ans[m]=0; printf("%s ", ans); } return 0; }