UVa 10561 (SG函数 递推) Treblecross

如果已经有三个相邻的X,则先手已经输了。

如果有两个相邻的X或者两个X相隔一个.,那么先手一定胜。

除去上面两种情况,每个X周围两个格子不能再放X了,因为放完之后,队手下一轮再放一个就输了。

最后当“禁区”布满整行,不能再放X了,那个人就输了。

每放一个X,禁区会把它所在的线段“分割”开来,这若干个片段就可以看做若干个游戏的和。

设g(x)表示x个连续格子对应的SG函数值,递推来求g(x):

g(x) = mex{ g(x-3), g(x-4), g(x-5), g(x-6) xor g(1), g(x-7) xor g(2)... }

g(0) = 0, g(1) = g(2) = g(3) = 1

枚举策略时,就是模拟下一步的状态,记录其中所有必败状态。

 1 #include <cstdio>
 2 #include <cstring>
 3
 4 const int maxn = 200;
 5 char s[maxn + 10];
 6 int g[maxn + 10], ans[maxn + 10];
 7 bool vis[maxn + 10];
 8
 9 bool winning(const char* s)
10 {
11     int n = strlen(s);
12     for(int i = 0; i < n-2; i++)//已经有三个相邻的X,先手输
13         if(s[i] == ‘X‘ && s[i+1] == ‘X‘ && s[i+2] == ‘X‘) return false;
14
15     bool no[n+1];
16     memset(no, false, sizeof(no));
17     for(int i = 0; i < n; i++) if(s[i] == ‘X‘)
18     {
19         for(int d = -2; d <= 2; d++)
20         {
21             if(i+d >= 0 && i+d < n)
22             {
23                 if(d != 0 && s[i+d] == ‘X‘) return true;//有两个X在彼此的禁区,先手胜
24                 no[i+d] = true;//设置禁区
25             }
26         }
27     }
28
29     no[n] = 1;
30     int sg = 0;
31     for(int i = 0; i < n; i++)
32     {
33         if(no[i]) continue;
34         int cnt = 0;
35         while(i < n && !no[i]) { i++; cnt++; }
36         sg ^= g[cnt];
37     }
38     return sg != 0;
39 }
40
41 int main()
42 {
43     //freopen("in.txt", "r", stdin);
44
45     g[0] = 0;
46     g[1] = g[2] = g[3] = 1;
47     for(int i = 4; i <= maxn; i++)
48     {//递推求函数g
49         memset(vis, false, sizeof(vis));
50         for(int j = 3; i-j >= 0; j++)
51         {
52             int v = 0;
53             v ^= g[i-j];
54             int x = j - 5;
55             if(x > 0) v ^= g[x];
56             vis[v] = true;
57
58             for(int j = 0; ; j++) if(!vis[j]) { g[i] = j; break; }
59         }
60     }
61
62     int T;
63     scanf("%d", &T);
64     while(T--)
65     {
66         scanf("%s", s);
67         if(!winning(s)) { printf("LOSING\n\n"); continue; }
68
69         puts("WINNING");
70         int n = strlen(s);
71         memset(ans, 0, sizeof(ans));
72         int p = 0;
73         for(int i = 0; i < n; i++) if(s[i] == ‘.‘)
74         {
75             s[i] = ‘X‘;
76             if(!winning(s)) ans[p++] = i+1;//后继必败状态便是先手下一步的策略
77             s[i] = ‘.‘;
78         }
79         for(int i = 0; i < p; i++)
80         {
81             if(i) printf(" ");
82             printf("%d", ans[i]);
83         }
84         printf("\n");
85     }
86
87     return 0;
88 }

代码君

时间: 2024-08-30 00:47:42

UVa 10561 (SG函数 递推) Treblecross的相关文章

Light OJ 1296 - Again Stone Game (博弈sg函数递推)

F - Again Stone Game Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Description Alice and Bob are playing a stone game. Initially there are n piles of stones and each pile contains some stone. Alice stars the

uva 1073 - Glenbow Museum(递推)

cocos2d-x升级到3.0后变化不小,除了API的变化(主要是函数和类名称变化,以及使用了C++11的不少特性,function/bind, lamda, std::thread-),创建和编译工程也做了一些简化调整.本文主要讨论一下cocos2d-x3.0 在android平台开发的环境设置及工程创建编译流程. 1.   初始设置 除了2.x所需要的python,jdk, android sdk和ndk之外,还需要部署apache-ant. 1)      在path中设置好java环境变

uva 1478 - Delta Wave(递推+大数+卡特兰数+组合数学)

题目链接:uva 1478 - Delta Wave 题目大意:对于每个位置来说,可以向上,水平,向下,坐标不能位负,每次上下移动最多为1, 给定n问说有多少种不同的图.结果对10100取模. 解题思路:因为最后都要落回y=0的位置,所以上升的次数和下降的次数是相同的,并且上升下降的关系满足出栈入栈的关系.即卡特兰数. 所以每次枚举i,表示有i个上升,i个下降,用组合数学枚举出位置,然后累加求和. C(2?in)?f(i)=C(2?i?2n)?f(i?1)?(n?2?i+1)?(n?2?i+2)

【UVA】12034-Race(递推,组合数打表)

递推公式,假设第一名有i个人并列,那么: f[n] = C(n,i) * f[n - i]; 打出1 ~ 1000的所有组合数,之后记忆化搜索,需要打表. 14026995 12034 Race Accepted C++ 0.032 2014-08-12 11:47:47 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector&g

UVA - 620Cellular Structure(递推)

题目:UVA - 620Cellular Structure(递推) 题目大意:只能给出三种细胞的增殖方式,然后给出最后细胞的增殖结果,最后问你这是由哪一种增殖方式得到的.如果可以由多种增殖方式得到,就输出题目中列出来的增殖方式靠前的那种. 解题思路:也是递推,细胞长度长的可以由细胞长度短的推得,并且这里第一种只能是长度为1的细胞才有可能,所以判断的时候可以3个判断,看能否与上面的增殖结果匹配,可以的话就记录下来,以后的长串就是由这样的短串再加上两个细胞继续往后推. 例如: BAABA 将A变为

uva 1485 - Permutation Counting(递推)

题目链接:uva 1485 - Permutation Counting 题目大意:给定n和k,要求求一个由1~n组成的序列,要求满足ai>i的i刚好有k个的序列种数. 解题思路:dp[j][i]表示长度为i,j个位置满足的情况. dp[j+1][i]+=dp[j][i]?(j+1); 1, (3), (4), 2: 括号位置代表ai>i,既满足位置,此时i = 4, j = 2. -> 1, (3), (4), 2, 5 1 种,在最后追加 -> 1, (5), (4), 2,

UVA - 10003Cutting Sticks(递推)

题目:UVA - 10003Cutting Sticks(递推) 题目大意:给根木棍长度l,现在要锯这根木棍,给出n个锯点,求怎样锯才能使得开销最小.例如 长度为10的木棍, 锯点2 4 7,那么如果按照这个顺序 , 首先显示由长度位10的木头先锯了2 ,开销就加10,然后锯完现在有[0,2]和[2,10]长度分别为2 ,8的木棍,现在要在4这个位置锯木头,就是在长度为8的木头上锯4这个位置,这样就加上8,然后又有长度为[2,4][4,10]的木头,最后要锯7的话,就需要开销加上6.所以开销就是

UVA 11021 - Tribles(概率递推)

UVA 11021 - Tribles 题目链接 题意:k个毛球,每个毛球死后会产生i个毛球的概率为pi,问m天后,所有毛球都死亡的概率 思路:f[i]为一个毛球第i天死亡的概率,那么 f(i)=p0+p1f(i?1)+p2f(i?1)2+...+pnf(i?1)n 然后k个毛球利用乘法定理,答案为f(m)k 代码: #include <stdio.h> #include <string.h> #include <math.h> const int N = 1005;

UVA 10288 - Coupons(概率递推)

UVA 10288 - Coupons 题目链接 题意:n个张票,每张票取到概率等价,问连续取一定次数后,拥有所有的票的期望 思路:递推,f[i]表示还差i张票的时候期望,那么递推式为 f(i)=f(i)?(n?i)/n+f(i?1)?i/n+1 化简后递推即可,输出要输出分数比较麻烦 代码: #include <cstdio> #include <cstring> #include <cmath> long long gcd(long long a, long lon