Treblecross(uva 10561)

题意:一个 1 × n 的棋盘,有 X 和 :,当棋盘上出现三个连续的X 时游戏结束,两人轮流操作,每次能把一个 : 变成 X,问先手必胜方案数以及先手可以放的位置。

/*
    对于先手,当有一个‘X‘时,它周围的两个格子就都不能放‘X‘了,所以这样游戏就被分成了几个部分,据此设定SG函数。
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 210
using namespace std;
int SG[N],len,v[N];
char s[N],tmp[N];
int calc(int x){
    if(x<0) return 0;
    if(SG[x]!=-1) return SG[x];
    int vis[N];
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=x;i++)
        vis[calc(i-3)^calc(x-i-2)]=1;
    for(int i=0;;i++)
        if(!vis[i])
            return SG[x]=i;
}
bool judge(int pos){
    if(s[pos]==‘X‘) return false;
    for(int i=0;i<len;i++) tmp[i]=s[i];
    tmp[pos]=‘X‘;
    for(int i=0;i+2<len;i++)//不知道为什么写i<len就不对,明明数组没有越界啊,奇了怪了。。。
        if(tmp[i]==‘X‘&&tmp[i+1]==‘X‘&&tmp[i+2]==‘X‘) return true;
    for(int i=0;i+1<len;i++)
        if(tmp[i]==‘X‘&&tmp[i+1]==‘X‘) return false;
    for(int i=0;i+2<len;i++)
        if(tmp[i]==‘X‘&&tmp[i+2]==‘X‘) return false;
    int ans=0,flag=0,w=2,last=-1;
    for(int i=len-1;i>=0;i--)
        if(tmp[i]==‘X‘){
            last=i;break;
        }
    for(int i=0,j;i<len;i++){
        if(i>last) w=0;
        if(tmp[i]==‘X‘){
            flag=2;continue;
        }
        for(j=i;j<len&&tmp[j]==‘.‘;j++);
        ans^=calc(j-i-w-flag);
        i=j-1;
    }
    return ans==0;
}
int main(){
    memset(SG,-1,sizeof(SG));
    int T;scanf("%d",&T);
    while(T--){
        int tot=0;
        scanf("%s",s);len=strlen(s);
        for(int i=0;i<len;i++)
            if(judge(i))
                v[++tot]=i;
        if(tot){
            printf("WINNING\n");
            for(int i=1;i<tot;i++)
                printf("%d ",v[i]+1);
            printf("%d\n",v[tot]+1);
        }
        else printf("LOSING\n\n");
    }
    return 0;
}
时间: 2024-07-31 14:23:36

Treblecross(uva 10561)的相关文章

UVA - 10561 Treblecross (SG定理)

Treblecross is a two player gamewhere the goal is to get three X in a row on a one-dimensional board. At the startof the game all cells in the board is empty. In each turn a player puts a X in an empty cell, and if that results in there beingthree X

并查集(UVA 1106)

POINT: 把每个元素看成顶点,则一个简单化合物就是一条无向边,若存在环(即k对组合中有k种元素),则危险,不应该装箱,反之,装箱: 用一个并查集维护连通分量集合,每次得到一种化合物(x, y)时检查x, y是否在同一集合中,如果是,拒绝,反之接受. 并查集 并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示. 集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并. -----------

逆向+两次bfs(UVA 1599)

为什么都说简单好想咧.坦白从宽看了人家的代码,涨了好多姿势,, http://blog.csdn.net/u013382399/article/details/38227917 被一个细节坑了.. 2147483647是0x7fffffff啊啊啊,7个f!!! 1 #include <iostream> 2 #include <sstream> 3 #include <cstdio> 4 #include <cstring> 5 #include <c

Carmichael Numbers(Uva 10006)

  Carmichael Numbers An important topic nowadays in computer science is cryptography. Some people even think that cryptography is the only important field in computer science, and that life would not matter at all without cryptography. Alvaro is one

D - Send a Table (UVA - 10820)

- 题目大意 给出一个n,求从1~n中任意两个数互质的对数为多少,(a,b)和(b,a)算两对. - 解题思路 构造一个欧拉函数的方法,然后用一个数组去存储下标,因为(a,b)和(b,a)算两对,所以每一个都加两倍,但(1,1)很特殊,所以最后减一就行了. - 代码 #include<iostream> #include<cmath> #include<cstring> using namespace std; const int MAX = 600000; int p

Minimum Sum LCM(uva 10791)

题意(就是因为读错题意而wa了一次):给一个数字n,范围在[1,2^23-1],这个n是一系列数字的最小公倍数,这一系列数字的个数至少为2 例如12,是1和12的最小公倍数,是3和4的最小公倍数,是1,2,3,4,6,12的最小公倍数,是12和12的最小公倍数……………… 那么找出一个序列,使他们的和最小,上面的例子中,他们的和分别为13,7,28,24……显然最小和为7 /* 我们很容易可以发现,将n唯一分解之后,把所有质因数乘以次数加起来就行了.比如:12=2^2*3^1,那么ans=2^2

B - Parentheses Balance (UVA - 673)

- 题目大意 给出两个字符()[],然后根据给的条件来判断. - 解题思路 根据给的三个条件,然后利用栈来处理,对于暂时没有后括号匹配的前括号压入栈,遇到后括号时看栈顶的前括号与其是否匹配,如果匹配则弹出该前括号.还要判断下最后栈里面是不是有剩下的没有匹配的前括号.(注意空字符也行) - 代码 #include<iostream> #include<stack> #include<cstring> using namespace std; int main() { in

紫书例题6-4 (UVa 11988)

题目链接:https://vjudge.net/problem/UVA-11988 题目大意:输入一串字符,并按照要求输出,遇到'['字符就将光标移动到开头,遇到']'字符就将光标移动到末尾. 思路: 题目不难懂,很明显的一个模拟就行,重点是如何取存储,这里选择使用链表,链表的具体定义可以去百度看一下,这里不做过多解释,可以简单理解为一个未知长度的数组,它可以借助指针在任意位置插入(删除). 这题具体的操作可以用草稿纸模拟一遍,我是看一位博主的blog明白的,原blog地址:https://bl

POJ 2250 Compromise (UVA 531)

LCS问题,基础DP. 让我很忧伤的WA了很多次.只是一个LCS问题,需要记录一下路径. 自己的想办法记录path出错,最后只好用标记. 没有什么优化,二维数组,递归打印,cin.eof() 来识别 end of file 标识. 至于单词用map 映射的.其实也用不着,直接二维string或者 二维char 然后strcmp 也行. Special Judge 交 UVA 531 奇怪的PE了... 然后改成 flag 标记 输出 空格.终于都AC了. #include<cstdio> #i