第一行给出可行操作集合大小为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;
}