SGU 153.Playing with matches

时间:2023-03-09 18:59:28
SGU 153.Playing with matches

题意:

一个取火柴游戏,可以取的数在一个集合S内,S必包含1,且不超过9个数,每个数都不大于9.最后取完者失败。

求n(n<10^9)根火柴时先取的胜利还是后取的胜利.


Solution:

典型的求SG函数的问题,由于n很大,而S集合的数比较少而且不超过10,所以可以通过找到它的循环节。

估算可知循环节不会超过512。一开始试图通过求S集合的公约数找到循环长度,但发现这是错误的。

下面的程序参考了别人的程序,暴力找循环节。

#include <stdio.h>
#include <string.h>
int a[12],n,m;
int SG[1060],hash[1060];
void GetSG(int Array[], int N)
{
int i, j;
memset(SG, 0, sizeof(SG));
for(i = 0; i <= N; i++)
{
memset(hash, 0, sizeof(hash));
for(j = 0; j<=m; j++)
{
if(i-Array[j]>0)
hash[SG[i - Array[j]]] = 1;
} for(j = 0; j <= N; j++)
{
if(hash[j] == 0)
{
SG[i] = j;
break;
}
}
}
} int main()
{
int T;
a[0]=1;
scanf("%d",&T);
while(T--)
{
memset(SG,0,sizeof(SG));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d",&a[i]);
GetSG(a,1050);
int k=0;
for(int l=512;l>=1;l--)
{
if(memcmp(SG+10,SG+10+l,l*sizeof(int))==0)
{
k=l;break;
}
}
if(n<9)
{
if(SG[n]>0)printf("FIRST PLAYER MUST WIN\n");
else printf("SECOND PLAYER MUST WIN\n");
}
else
{
if(SG[9+(n-9)%k]>0)printf("FIRST PLAYER MUST WIN\n");
else printf("SECOND PLAYER MUST WIN\n");
}
}
return 0;
}