S-Nim
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2883 Accepted Submission(s): 1280
The starting position has a number of heaps, all containing some, not necessarily equal, number of beads.
The players take turns chosing a heap and removing a positive number of beads from it.
The first player not able to make a move, loses.
Arthur and Caroll really enjoyed playing this simple game until they recently learned an easy way to always be able to find the best move:
Xor the number of beads in the heaps in the current position (i.e. if we have 2, 4 and 7 the xor-sum will be 1 as 2 xor 4 xor 7 = 1).
If the xor-sum is 0, too bad, you will lose.
Otherwise, move such that the xor-sum becomes 0. This is always possible.
It is quite easy to convince oneself that this works. Consider these facts:
The player that takes the last bead wins.
After the winning player's last move the xor-sum will be 0.
The xor-sum will change after every move.
Which means that if you make sure that the xor-sum always is 0 when you have made your move, your opponent will never be able to win, and, thus, you will win.
Understandibly it is no fun to play a game when both players know how to play perfectly (ignorance is bliss). Fourtunately, Arthur and Caroll soon came up with a similar game, S-Nim, that seemed to solve this problem. Each player is now only allowed to remove a number of beads in some predefined set S, e.g. if we have S =(2, 5) each player is only allowed to remove 2 or 5 beads. Now it is not always possible to make the xor-sum 0 and, thus, the strategy above is useless. Or is it?
your job is to write a program that determines if a position of S-Nim is a losing or a winning position. A position is a winning position if there is at least one move to a losing position. A position is a losing position if there are no moves to a losing position. This means, as expected, that a position with no legal moves is a losing position.
2 游戏C:
2 甲乙两人面对若干排石子,其中每一排石子的数目可以任意确定。例如图2所示的初始局面:共n=3排,其中第一排的石子数a1=7,第二排石子数a2=3,第三排石子数a3=3。两人轮流按下列规则取走一些石子,游戏的规则如下:
Ø 每一步必须从某一排中取走两枚石子;
Ø 这两枚石子必须是紧紧挨着的;
Ø 如果谁无法按规则取子,谁就是输家。
G 在游戏C中,g(7)={#(5), #(1, 4), #(2, 3)}。
G
Ø 若#S=0,则无论先行者如何取子S→T,都有#T≠0。
& 设S=(a1, a2, …, an),由于先行者只能选择一堆石子,不妨设选择了a1;
& 因为#S=f(a1)+#(a2, …, an)=0,所以f(a1)=#(a2, …, an);
& 先行者可能将局面(a1)变为局面(b1, …, bm),#(b1, …, bm)属于集合g(a1);
& 设这时的局面为T,我们有T=(b1, …, bm)+(a2, …, an);
& #T=#(b1, …, bm)+#(a2, …, an)=#(b1, …, bm)+f(a1);
& 如果要求#T≠0,则必然有#(b1, …, bm)≠f(a1);
& 因此,函数f(a1)的值,不属于集合g(a1)。(充要)
G
Ø 若#S≠0,则先行者必然存在一种取子方法S→T,且#T=0。
& 设S=(a1, a2, …, an),p=#S=f(a1)+f(a2)+…+f(an);
& 因为p≠0,所以必然存在k,使得f(ak)+p<f(ak),不妨设k=1,f(a1)+p=x;
& 因为p=#S=f(a1)+#(a2, …, an),故(a2, …, an)=p+f(a1)=x;
& 如果先行者把局面(a1)变为局面(b1, …, bm),#(b1, …, bm)属于集合g(a1);
& 设这时的局面为T,我们有T=(b1, …, bm)+(a2, …, an);
& #T=#(b1, …, bm)+#(a2, …, an)=#(b1, …, bm)+x;
& 如果要使#T=0,相当于要找到(b1, …, bm),使得#(b1, …, bm)等于x;
& 如果可以保证x属于集合g(a1),则肯定可以找到相应的的(b1, …, bm);
& 因为x<f(a1),所以,x属于集合{0, 1, …, f(a1)–1};
& 如果集合g(a1)包含集合{0, 1, …, f(a1)–1},则x一定属于g(a1)。(充分)
G
2 函数f满足要求的一个充分条件
Ø f(a1)不属于集合g(a1)。
Ø 集合g(a1)包含集合{0, 1, …, f(a1)–1}。
G 如果g(a1)={0, 1, 2, 5, 7, 8, 9},则f(a1)=3,满足要求。
F 用大写字母N表示非负整数集,即N={0, 1, 2, …}。
F 令N为全集,集合G(x)表示集合g(x)的补集。
F 定义函数f(n):f(n)=min{G(n)},即f(n)等于集合G(n)中的最小数。
F 设局面S=(a1, a2, …, an),#S=f(a1)+f(a2)+…+f(an),采用二进制数的加法。
* 若#S=0,则S负;若#S≠0,则S胜。
G 游戏C的f值:
Ø g(0)={},G(0)={0, 1, …},f(0)=0;
Ø g(1)={},G(1)={0, 1, …},f(1)=0;
Ø g(2)={#(0)}={f(0)}={0},G(2)={1, 2, …},f(2)=1;
Ø g(3)={#(1)}={f(1)}={0},G(2)={1, 2, …},f(3)=1;
Ø g(4)={#(2), #(1, 1)}={f(2), f(1)+f(1)}={1, 0},G(4)={2, 3, …},f(4)=2;
Ø g(5)={#(3), #(1, 2)}={f(3), f(1)+f(2)}={1, 1},G(5)={0, 2, 3, …},f(5)=0;
Ø g(6)={#(4), #(1, 4), #(2, 2)}={2, 1, 0},G(6)={3, 4, …},f(6)=3;
Ø g(7)={#(4), #(1, 4), #(2, 3)}={2, 2, 0},G(7)={1, 3, 4, …},f(7)=1;
G 图2所示的局面S=(7, 3, 3),有#S=f(7)+f(3)+f(3)=1+1+1=1,故S胜。
游戏C的初始局面S=(3, 4, 6),有#S=1+2+3=01+10+11=0,故S负。
{
int i,t;
bool g[101];
memset(g,false,sizeof(g));
for(i=0;i<k;i++)
{
t=n-num[i];
if(t<0)
break;
if(sg[t]==-1)
sg[t]=mex(t);
g[sg[t]]=true;
}
for(i=0;;i++)
if(!g[i])
return i;
}
#include<cstdio>
#include<algorithm>
using namespace std;
int sg[10001];
bool g[101];
int k,num[101];
int mex(int n)
{
int i,t;
memset(g,false,sizeof(g));
for(i=0;i<k;i++)
{
t=n-num[i];
if(t<0)
break;
if(sg[t]==-1)
sg[t]=mex(t);
g[sg[t]]=true;
}
for(i=0;;i++)
if(!g[i])
return i;
}
int main()
{
int i,n,l,digit,ans;
while(~scanf("%d",&k),k)
{
for(i=0;i<k;i++)
scanf("%d",num+i);
sort(num,num+k);
scanf("%d",&n);
memset(sg,-1,sizeof(sg));
while(n--)
{
ans=0;
scanf("%d",&l);
while(l--)
{
scanf("%d",&digit);
ans^=mex(digit);
}
if(ans==0)
printf("L");
else
printf("W");
}
printf("\n");
}
return 0;
}
#include<cstdio>
#include<algorithm>
using namespace std;
int sg[10001];
int k,num[101];
int mex(int n)
{
int i,t;
bool g[101];
memset(g,false,sizeof(g));
for(i=0;i<k;i++)
{
t=n-num[i];
if(t<0)
break;
if(sg[t]==-1)
sg[t]=mex(t);
g[sg[t]]=true;
}
for(i=0;;i++)
if(!g[i])
return i;
}
int main()
{
int i,n,l,digit,ans;
while(~scanf("%d",&k),k)
{
for(i=0;i<k;i++)
scanf("%d",num+i);
sort(num,num+k);
scanf("%d",&n);
memset(sg,-1,sizeof(sg));
while(n--)
{
ans=0;
scanf("%d",&l);
while(l--)
{
scanf("%d",&digit);
ans^=mex(digit);
}
if(ans==0)
printf("L");
else
printf("W");
}
printf("\n");
}
return 0;
}