HDU 3980 (SG 环变成链 之前的先手变成后手)

题意
两个人在一个由 n 个玻璃珠组成的一个圆环上玩涂色游戏,游戏的规则是:
1、每人一轮,每轮选择一个长度为 m 的连续的、没有涂过色的玻璃珠串涂色
2、不能涂色的那个人输掉游戏

Aekdycoin 先手

开始时候是一个环,第一个人涂色后就变成了链,这时候就可以使用尼姆博弈了。但是注意一点此时第二个人应该变成尼姆博弈中的先手了。

第一次涂色后 变成 abcdxyzk 先手


n < m 先手无法涂 后手胜

假如变成链后的n= 5 , m=2,则后继状态有

状态1 拿最开始的两个 变成   ***  

状态2  变成 * **

状态3   ** *

状态4  ***


Sample Input
2
3 1 // n m
4 2

Sample Output
Case #1: aekdycoin
Case #2: abcdxyzk

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <cstring>
 4 using namespace std ;
 5 
 6 int sg[1010];
 7 bool vis[1010];
 8 int m , n ; //每次取m个
 9 int mex(int n) //求N的SG值
10 {
11     if(sg[n] != -1)return sg[n];
12     if(n < m)return sg[n] = 0;
13     memset(vis,false,sizeof(vis));
14     for(int i = m;i <= n;i++)
15         vis[mex(i-m)^mex(n-i)] = true;
16     for(int i = 0;;i++)
17         if(vis[i] == false)
18         {
19             sg[n] = i;
20             break;
21         }
22     return sg[n];
23 }
24 
25 int main ()
26 {
27     int T ;
28     scanf("%d" , &T) ;
29     int iCase = 0 ;
30     while(T--)
31     {
32         scanf("%d%d",&n,&m);
33         iCase++;
34         if(n < m)  //只有n个 但是要涂m个  先手无法涂m个  先手败 
35         {
36             printf("Case #%d: abcdxyzk
",iCase);
37             continue;
38         }
39         n -= m;
40         memset(sg,-1,sizeof(sg));
41         for(int i = 0;i <= n;i++)
42             sg[i] = mex(i);
43         if(sg[n] == 0)
44            printf("Case #%d: aekdycoin
",iCase);  //后手胜 
45         else 
46            printf("Case #%d: abcdxyzk
",iCase);
47         
48     }
49     
50     
51     return 0 ;
52 }
View Code
原文地址:https://www.cnblogs.com/mengchunchen/p/4491252.html