第一行给出可行操作集合大小为k,然后k个数表示一次能在一堆里取这些数量的石子。先拿完者赢。
第二行一个数m表示将会进行m次游戏。
下面m行,每行第一个数n表示石子的堆数,后面n堆石子的数量。每次游戏先手赢输出W,否则输出L。每个样例所有游戏次数输出在一行。
求SG函数模板
递归
//N为一堆里最大石子数量 //M为可操作集合的最大数量 //x为实际一堆里多少石子 //k为实际可操作集合s为多大 //注意:sg需要初始化为-1,每个集合初始化一遍即可,s需要初始化由小到大排序 int s[N], sg[N], k; int getsg(int x) { int i; if(sg[x]!=-1) return sg[x]; bool vis[M]; memset(vis,0,sizeof(vis)); for(i=0; i < k && x>=s[i]; i++) vis[getsg(x-s[i])]=1; for(i=0; ; i++) { if(!vis[i]) { sg[x]=i; break; } } return sg[x]; }
打表
//N为一堆里最大石子数量 //M为可操作集合的最大数量 //n表示要打多大的表 //k为实际可操作集合s为多大 //注意:s需要初始化由小到大排序 bool mex[M]; int sg[N], s[M], k; void getsg(int n) { memset(sg, 0, sizeof sg); int i, j; for(i = 0; i <= n; i++) { memset(mex, 0, sizeof mex); for(j = 0; j < k && i >= s[j]; j++) { mex[sg[i - s[j]]] = 1; } for(j = 0; ; j++) { if(mex[j] == 0) { sg[i] = j; break; } } } }
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; #define N 110//可操作集合的最大数量 #define M 10010//一堆最大石子数量 int s[110];//有小到大排序 int sg[10010];// bool mes[10010]; void get_sg(int n){//n代表实际可操作集合大小 memset(sg,0,sizeof(sg)); for(int i=0;i<10001;i++){ memset(mes,0,sizeof(mes)); for(int j=0;j<n&&s[j]<=i;j++){ mes[sg[i-s[j]]]=1; } for(int j=0;j<10001;j++){ if(mes[j]==0){ sg[i]=j; break; } } } } int main(){ int k; while(scanf("%d",&k)&&k){ for(int i=0;i<k;i++) scanf("%d",&s[i]); sort(s,s+k); get_sg(k); int m; scanf("%d",&m); while(m--){ int num; scanf("%d",&num); int tmp=0; for(int i=0;i<num;i++){ int x; scanf("%d",&x); tmp^=sg[x]; } if(tmp) printf("W"); else printf("L"); } printf("\n"); } return 0; }