题目
n堆石子,每次可以选一堆石子取若干(像Nim游戏一样)
也可以把一堆石子分成三堆非空石子,
取走最后一颗石子的胜,给定局面问谁必胜
思路来源
https://blog.csdn.net/Code92007/article/details/87892307
题解
Multi-SG打表,考虑三个子状态为后继即可
先把100以内表打出来,
发现除以8余7的正整数和整除8的正整数的sg值互换了
其余就是本身,这就是规律
代码1(打表找SG规律)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e3+5;
int T,n,sg[105];
bool vis[105];
void getsg()
{
sg[0]=0;sg[1]=1;
for(int i=2;i<=100;++i)
{
memset(vis,0,sizeof(vis));
for(int j=0;j<=i-1;++j)
{
vis[sg[j]]=1;
}
for(int k=1;k<=i;++k)
{
for(int l=1;l<=i;++l)
{
if(k+l>i)break;
for(int m=1;m<=i;++m)
{
if(k+l+m>i)break;
if(k+l+m==i)vis[sg[k]^sg[l]^sg[m]]=1;
}
}
}
for(int v=0;;++v)
{
if(!vis[v])
{
sg[i]=v;
break;
}
}
}
for(int i=0;i<=100;++i)
{
printf("sg[%3d]:%3d ",i,sg[i]);
if((i+1)%10==0)puts("");
}
}
int main()
{
getsg();
return 0;
}
代码2(输出)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int getsg(int x)
{
if(x&&x%8==0)return x-1;
if((x+1)%8==0)return x+1;
return x;
}
int t;
int main()
{
scanf("%d",&t);
while(t--)
{
int n,ans=0;
scanf("%d",&n);
for(int i=0;i<n;++i)
{
int v;
scanf("%d",&v);
ans^=getsg(v);
}
if(ans)puts("First player wins.");
else puts("Second player wins.");
}
return 0;
}