BZOJ3497 : Pa2009 Circular Game

令先手爲$A$,後手爲$B$,將相鄰同色棋子合併成塊,首先特判一些狀況:blog

  1. 若是全部格子都是滿的,那麼顯然$A$必敗。
  2. 不然若是全部塊都只有一個棋子,那麼顯然平局。
  3. 枚舉$A$的第一步操做,若是能夠使得B沒法操做,那麼顯然$A$必勝。

無視全部大小爲$1$的塊,考慮剩下塊裏相鄰兩塊,它們往外擴張比往內縮更優:遊戲

  • 若是是形如[A_A]___B__A__BA____B___[AA_A],兩邊同色,因此中間這些塊(包括位置)能夠刪除,不影響遊戲結果。
  • 若是是形如[A_A]___B__A__B_A__[BB_B],兩邊異色,那麼相鄰兩塊相互靠近更優,能夠等效替代成[A_A]___[BB][AA]__[BB][AA]__[BB_B]。

通過上述轉化後,再也不存在大小爲$1$的塊,當存在大小至少爲$3$且內部存在空隙的自由塊時,該塊顯然能夠永遠操做下去。假設不存在自由塊,那麼顯然不會平局,遊戲等價於每堆石子數爲相鄰兩塊間距的Nim遊戲。string

分如下狀況討論:io

  1. $A$能夠經過至多一步操做獲得自由塊,且能夠阻止$B$獲得自由塊,此時結果爲$A$勝。
  2. $AB$一開始都沒有自由塊,但均可以經過一步獲得,$A$先堵$B$,$B$再堵$A$後雙方都沒有自由塊,可是此時Nim遊戲$A$勝,則最終$A$勝。
  3. $AB$都無法經過一步操做獲得自由塊,可是此時Nim遊戲$A$勝,則最終$A$勝。
  4. $A$能夠經過至多一步操做獲得自由塊,可是阻止不了$B$獲得自由塊,此時結果爲平局。
  5. $A$沒法獲得自由塊,也阻止不了$B$獲得自由塊,此時結果爲$B$勝。
  6. 雙方都無法獲得自由塊,可是此時Nim遊戲$B$勝,則最終$B$勝。

時間複雜度$O(B+C)$。class

 

#include<cstdio>
#include<cstring>
#define CLR(x) memset(x,0,sizeof x)
const int N=1000010,BUF=12000000;
char Buf[BUF],*buf=Buf;
int Case,m,n,ce,A,B,i,j,k,o,x,st,a[N],b[N],can10,can11,can01,can00;
struct P{
  int x;char col;
  P(){}
  P(int _x,char _col){x=_x,col=_col;}
}q[N];
struct E{
  int len,cnt,dis;char col;
  E(){}
  E(int _len,int _cnt,int _dis,char _col){len=_len,cnt=_cnt,dis=_dis,col=_col;}
  bool free(){return len>cnt&&cnt>=3;}
}e[N];
int cfree[2],cmove[2],cnt[2],cmay[2],sum[2],CFREE,CMAY0,CMAY1;
inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
inline void cal(){
  if(e[0].col==e[ce-1].col){
    ce--;
    e[0].len+=e[ce].len+e[ce].dis;
    e[0].cnt+=e[ce].cnt;
  }
  CLR(cfree),CLR(cmove),CLR(cnt),CLR(cmay);CLR(sum);
  for(i=0;i<ce;i++){
    cnt[e[i].col]++;
    if(e[i].free())cfree[e[i].col]++,cmove[e[i].col]++,cmay[e[i].col]++;
    if(e[i].len>e[i].cnt)cmove[e[i].col]++;
    if(e[i].dis){
      cmove[e[i].col]++;
      if(e[i].cnt>=3){
        cmay[e[i].col]++;
        sum[e[i].col]^=e[i].dis;
      }
    }
    if(e[(i-1+ce)%ce].dis){
      cmove[e[i].col]++;
      if(e[i].cnt>=3){
        cmay[e[i].col]++;
        sum[e[i].col]^=e[(i-1+ce)%ce].dis;
      }
    }
  }
}
inline bool can_block_b(){
  if(cfree[1])return 0;
  if(cmove[1]>1)return 0;
  for(i=0;i<ce;i++)if(e[i].col==1&&e[i].len>e[i].cnt)return 0;
  for(i=0;i<ce;i++)if(e[i].col==1){
    if(e[i].dis&&e[(i+1)%ce].len>1)return 1;
    if(e[(i-1+ce)%ce].dis&&e[(i-1+ce)%ce].len>1)return 1;
  }
  return 0;
}
inline void change(int x,int y){
  CFREE=cfree[0],CMAY0=cmay[0],CMAY1=cmay[1];
  if(e[x].cnt>=3)CFREE++,CMAY0++;
  if(e[y].cnt>=3&&!e[y].free())CMAY1--;
}
inline int solve(){
  read(m),read(A),read(B);
  for(i=1;i<=A;i++)read(a[i]);
  for(i=1;i<=B;i++)read(b[i]);
  //Circle is full, so A can't move
  if(A+B==m)return -1;
  n=0;
  i=j=1;
  while(i<=A&&j<=B)if(a[i]<b[j])q[++n]=P(a[i++],0);else q[++n]=P(b[j++],1);
  while(i<=A)q[++n]=P(a[i++],0);
  while(j<=B)q[++n]=P(b[j++],1);
  ce=0;
  for(i=1;i<=n;i=j+1){
    for(j=i;j<n&&q[i].col==q[j+1].col;j++);
    e[ce++]=E(q[j].x-q[i].x+1,j-i+1,q[j+1].x-q[j].x-1,q[i].col);
  }
  e[ce-1].dis=q[1].x-q[n].x-1+m;
  cal();
  //All blocks' length is 1, draw
  for(i=0;i<ce;i++)if(e[i].len!=1)break;
  if(i>=ce)return 0;
  //A can't move
  if(!cmove[0])return -1;
  //A can make B not to move
  if(can_block_b())return 1;
  for(i=0;i<ce;i++)if(e[i].len>1){st=i;break;}
  for(i=0;i<ce;i=j){
    for(j=i+1;j<=ce;j++)if(e[(st+j)%ce].len>1)break;
    int l=(st+i)%ce;
    if(e[l].col!=e[(st+j)%ce].col)for(k=i+1,o=1;k<j;k++,o^=1){
      x=(st+k)%ce;
      if(o)e[x].dis=0;
      e[x].len=e[x].cnt=2;
    }else{
      e[l].len+=e[l].dis;
      e[l].dis=0;
      for(k=i+1,o=1;k<j;k++,o^=1){
        x=(st+k)%ce;
        if(o)cnt[e[x].col]--;
        e[l].len+=e[x].len+e[x].dis;
        e[l].cnt+=e[x].cnt;
      }
    }
  }
  //No such blocks
  if(!cnt[0])return -1;
  if(!cnt[1])return 1;
  for(i=n=0;i<ce;i++)if(e[i].len>1)e[n++]=e[i];
  for(ce=i=1;i<n;i++)if(e[i].col==e[ce-1].col){
    e[ce-1].len+=e[i].len+e[ce-1].dis;
    e[ce-1].cnt+=e[i].cnt;
    e[ce-1].dis=e[i].dis;
  }else e[ce++]=e[i];
  cal();
  //A can't move
  if(!cmove[0])return -1;
  //A can make B not to move
  if(can_block_b())return 1;
  can10=can11=can01=can00=0;
  CFREE=cfree[0],CMAY0=cmay[0],CMAY1=cmay[1];
  if(CFREE){
    if(!CMAY1)can10=1;
    if(cfree[1])can11=1;
  }
  for(x=i=0;i<ce;i++)x^=e[i].dis;
  for(i=0;i<ce;i++)if(e[i].col==0){
    if(e[i].dis){
      change(i,(i+1)%ce);
      if((CMAY0>1||CFREE)&&!CMAY1)can10=1;
      if(CFREE&&CMAY1)can11=1;
      if(!CFREE&&CMAY1)can01=1;
      if(!CMAY1&&x==e[i].dis)can00=1;
      if(!CFREE&&CMAY0==1&&!CMAY1)if(x^e[i].dis^sum[0])can00=1;
    }
    if(e[(i-1+ce)%ce].dis){
      change(i,(i-1+ce)%ce);
      if((CMAY0>1||CFREE)&&!CMAY1)can10=1;
      if(CFREE&&CMAY1)can11=1;
      if(!CFREE&&CMAY1)can01=1;
      if(!CMAY1&&x==e[(i-1+ce)%ce].dis)can00=1;
      if(!CFREE&&CMAY0==1&&!CMAY1)if(x^e[(i-1+ce)%ce].dis^sum[0])can00=1;
    }
  }
  if(can10)return 1;
  if(can00)return 1;
  if(can11)return 0;
  if(can01)return -1;
  return x?1:-1;
}
int main(){
  fread(Buf,1,BUF,stdin);read(Case);
  while(Case--){
    int x=solve();
    if(x>0)puts("B");
    if(!x)puts("R");
    if(x<0)puts("C");
  }
  return 0;
}
相關文章
相關標籤/搜索