SG函数应用模板题,但还是想写一下(SG入门从此起步)
大意是:有很多堆糖果,每个人可以在一堆取走任意多个糖果,或者将其分成3个非空堆。最后取走为胜,问先手胜还是后手。
主要在用SG打表上,用SG输出每个值的mex,从中找规律。
#include <bits/stdc++.h>
#define maxn 1000
using namespace std;
///题目中要求的是可以分解为三堆,或者可以取走任意个
int sg[maxn];
bool vis[maxn];
int makesg(int num)
{
if(sg[num]!=-1)
return sg[num];
memset(vis,0,sizeof(vis));
for(int i=1;i<num;i++)///sg的值小于num的值
{
int a=makesg(i);
for(int j=1;j<num-i;j++)
{
int b=num-i-j;///根据题目要求将一堆分成三堆
int c=makesg(j);
int d=makesg(b);
int sgg=a^d^c;
vis[sgg]=1;///这个子状态已经找过了
}
vis[a]=1;
}
vis[0]=1;
for(int i=1;;i++)
{
if(!vis[i]) return i;///一直未出现的即是mes{}中未出现的最小的非负整数
}
}
int main()
{
memset(sg,-1,sizeof(sg));
for(int i=1;i<=100;i++)
{
sg[i]=makesg(i);
}
for(int i=1;i<=100;i++)
{
printf("sg[%d]=%d\n",i,sg[i]);
}
}
通过打表可知:8的倍数和7的倍数的SG值会互换,其他的SG值和本值相同,故AC代码如下:
#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
typedef long long ll;
ll T;
ll x;
ll N;
ll sg(ll x)
{
if(x%8==0)return x-1;
if(x%8==7)return x+1;
return x;
}
int main()
{
scanf("%I64d",&T);
while(T--)
{
scanf("%I64d",&N);
ll ans=0;
for(int i=0;i<N;i++)
{
scanf("%I64d",&x);
ans^=sg(x);
}
if(ans)printf("First player wins.\n");
else printf("Second player wins.\n");
}
return 0;
}