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;
}

  

posted @ 2014-07-22 09:30  keambar  阅读(284)  评论(0编辑  收藏  举报