zoukankan      html  css  js  c++  java
  • UVA 10561 Treblecross

      题目大意:有一个'.'、'X'串,现在两人轮流把'.'改成'X',先连出三个连续的'X'的胜,求先手是否有必胜策略。如果有,输出所有可行的第一步。串长≤200,保证初始无三连'X'。

      博弈题真有意思,也好久没有做过了,搞得我连SG函数的性质都记反了,真尬。

      首先可以看出本来就有二连'X'的肯定要选掉,而且肯定是第一步选,就把直接获胜的判掉了。所以下面考虑的都是不能一步出解的。

      不难分析出,在'X'的左右两格都不能放,所以原串被分割成了很多个不相交的区间,而且这些区间互不影响,这个就很显然是用博弈知识来解决了。

      很明显一个区间的胜负态只与这个区间的长度有关,所以SG(x)表示长度为x的区间的SG函数值。

      首先可以推出SG(0)=0,SG(1)=SG(2)=SG(3)=1。(就是这里让我算了好久,mmp)

      根据SG函数的定义,状态x的SG值应该是所有后继状态的集合的mex。

      于是大力找出所有后继状态(枚举这次改哪个地方)+SG定理求出mex就可以了。打表发现串长不超过200时,SG值不到20,随便怎么搞就过去了。

      这个时候有没有解已经可以用SG定理知道了,但输出方案……

      反正串长只有那么点,直接暴力枚举答案,同样用SG定理判断即可。

      最后就是这题卡输出格式,丧心病狂,而且代码根本压不下来。

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #include    <complex>
    #include    <stack>
    #define LL long long int
    #define dob double
    #define FILE "10561"
    using namespace std;
    
    const int N = 210;
    int n,vis[20],sg[N];
    char S[N];bool os[N];
    
    inline int gi(){
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    
    inline int prepare(){
      sg[0]=0;sg[1]=sg[2]=sg[3]=1;
      for(int i=1;i<=200;++i){
        memset(vis,0,sizeof(vis));
        vis[sg[i-3]]=vis[sg[i-4]]=vis[sg[i-5]]=1;
        for(int j=1;j<=i-5-j;++j)
          vis[sg[j]^sg[i-5-j]]=1;
        for(int j=0;j<=200;++j)
          if(!vis[j]){sg[i]=j;break;}
      }
      return gi();
    }
    
    inline bool Is(int x){
      if(x<0 || x>n)return false;
      return S[x]=='X';
    }
    
    inline bool canput(int x){
      if(Is(x-2) || Is(x-1) || Is(x) || Is(x+1) || Is(x+2))
        return false;
      return x<=n;
    }
    
    inline bool check(int ans=0){
      for(int l=1,r=1;l<=n;l=++r)
        if(canput(l)){
          for(;r<=n;++r)
            if(!canput(r+1))break;
          ans^=sg[r-l+1];
        }
      return ans;
    }
    
    inline void solve(int flg=0){
      scanf("%s",S+1);n=strlen(S+1);
      for(int i=3;i<=n;++i)
        if(Is(i-2)+Is(i-1)+Is(i)>=2)
          flg=1;
      if(flg){
        printf("WINNING
    ");flg=0;
        for(int i=1;i<=n;++i)
          if(!Is(i))
            if((Is(i-2) && Is(i-1)) || (Is(i-1) && Is(i+1)) || (Is(i+1) && Is(i+2))){
              if(flg)printf(" ");
              printf("%d",i);flg=1;
            }
        printf("
    ");return;
      }
      if(!check()){printf("LOSING
    
    ");return;}
      printf("WINNING
    ");flg=0;
      for(int i=1;i<=n;++i)
        if(canput(i)){
          S[i]='X';
          if(!check()){
            if(flg)printf(" ");
            printf("%d",i);flg=1;
          }
          S[i]='.';
        }
      printf("
    ");
    }
    
    int main()
    {
      freopen(FILE".in","r",stdin);
      freopen(FILE".out","w",stdout);
      int Case=prepare();while(Case--)solve();
      fclose(stdin);fclose(stdout);
      return 0;
    }
    Treblecross
  • 相关阅读:
    Xcode 10 关于 CocoaPods 安装失败的问题RuntimeError
    iOS 解决xcode设置全局断点后 执行视频播放时自动进入断点cxa_throw
    iOS swift String 换行显示
    iOS wkWebView点击链接无反应
    iOS swift跑马灯滚动可以点击
    iOS swift版本无限滚动轮播图
    iOS swift中比较模型数组是否相等
    iOS valueForKeyPath快速计算求和、平均值、最大、最小
    iOS 全屏播放网页视频退出后状态栏被隐藏
    vacabulary1
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/7719108.html
Copyright © 2011-2022 走看看