hdu3980Paint Chain(SG)

来源:互联网 发布:js大禹防水涂料 编辑:程序博客网 时间:2024/05/19 15:25

题意:

有n个珠子,每次必须涂色m个连续的。这 n个珠子是个环。询问胜负情况

思路:

对于是个环的情况,我们可以首先拿出一组m,如果n<m,先手必输。否则的话跑sg函数,注意此时sg函数跑的是后手的sg情况。

这样环就转变为了链结构,对于一条链,sg[ i<m]=0, sg[m]=1,  每一个sg情况等于子问题的异或。

因此转变为了 对于i>m的情况下, 如果从中拿出m个连续珠子。

子问题是: 假如在j处取这m个珠子, 左侧 j,右侧 i-m-j


#include <stdio.h>#include <string.h>#define N 20const int MAXN=1005;int f[N],SG[MAXN],S[MAXN];//f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理//SG[]:0~n的SG函数值//S[]:为x后继状态的集合void  getSG(int n,int m){    int i,j;    memset(SG,0,sizeof(SG));    //因为SG[0]始终等于0,所以i从1开始    SG[m]=1;    for(i = m+1; i <= n; i++)    {        //每一次都要将上一状态 的 后继集合 重置        memset(S,0,sizeof(S));        for(j = 0; j<i-m; j++)            S[SG[j]^SG[i-m-j]] = 1;  //将后继状态的SG函数值进行标记        for(j = 0;; j++)            if(!S[j])            {                //查询当前后继状态SG值中最小的非零值                SG[i] = j;                break;            }    }}int main(){    int n,m,k;    int cs=1;    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n ,&m);        printf("Case #%d: ",cs++);        if(n<m)        {            printf("abcdxyzk\n");        }        else        {            n=n-m;            getSG(n,m);            if(SG[n])            {                printf("abcdxyzk\n");            }            else                printf("aekdycoin\n");        }    }    return 0;}


原创粉丝点击