UVA 10561 Treblecross

  題目大意:有一個'.'、'X'串,如今兩人輪流把'.'改爲'X',先連出三個連續的'X'的勝,求先手是否有必勝策略。若是有,輸出全部可行的第一步。串長≤200,保證初始無三連'X'。ios

  博弈題真有意思,也很久沒有作過了,搞得我連SG函數的性質都記反了,真尬。ide

  首先能夠看出原本就有二連'X'的確定要選掉,並且確定是第一步選,就把直接獲勝的判掉了。因此下面考慮的都是不能一步出解的。函數

  不難分析出,在'X'的左右兩格都不能放,因此原串被分割成了不少個不相交的區間,並且這些區間互不影響,這個就很顯然是用博弈知識來解決了。spa

  很明顯一個區間的勝負態只與這個區間的長度有關,因此SG(x)表示長度爲x的區間的SG函數值。code

  首先能夠推出SG(0)=0,SG(1)=SG(2)=SG(3)=1。(就是這裏讓我算了很久,mmp)blog

  根據SG函數的定義,狀態x的SG值應該是全部後繼狀態的集合的mex。get

  因而大力找出全部後繼狀態(枚舉此次改哪一個地方)+SG定理求出mex就能夠了。打表發現串長不超過200時,SG值不到20,隨便怎麼搞就過去了。string

  這個時候有沒有解已經能夠用SG定理知道了,但輸出方案……it

  反正串長只有那麼點,直接暴力枚舉答案,一樣用SG定理判斷便可。io

  最後就是這題卡輸出格式,喪心病狂,並且代碼根本壓不下來。

#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\n");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("\n");return;
  }
  if(!check()){printf("LOSING\n\n");return;}
  printf("WINNING\n");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("\n");
}

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
相關文章
相關標籤/搜索