[bzoj4600][SDOI2016]硬幣遊戲

4600: [Sdoi2016]硬幣遊戲

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 7 Solved: 5
[Submit][Status][Discuss]

首先我們可以發現,每個數的形式都是這樣的:c2a3b
如果我們建立一個二維的座標系,橫座標表示a ,縱座標表示b ,可以這樣表示的原因是因爲這個遊戲的規則。每次翻的點都是c 相同的。所以就與c 沒什麼關係了。
這樣我們令sg[i][j] 表示i 這個點與之前所有點的狀態不一樣,翻這個點的sg 值是多少。這個在求的時候可以暴力枚舉所有的後繼狀態。
有一個問題就是在一個後繼狀態中會被翻的所有的點得sg 值怎麼表示?在計算答案的過程中翻一個點會不會對前面的點有影響?
其實這兩個是一個問題,就是這個點和它的後繼點是否是獨立的。
其實是獨立的。我們可以看求sg 的過程,假如我們翻了這個點後會對前面有些點產生影響,但是對於某一個點來說被翻得總次數是一定的,只是先後順序不同,所以無論順序是怎樣這個點的狀態都會是這個,也就是說這個點可以看成是獨立的。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool flag[500];
int T,n,maxq,SG[20][20];
inline void solve2(){
    int i,j,p,q,k,x=0,y=0,o;
    o=n;while(o>=2) ++x,o/=2;
    o=n;while(o>=3) ++y,o/=3;
    memset(SG,0,sizeof(SG));
    for(i=0;i<=x;++i)
      for(j=0;j<=y;++j){
        memset(flag,0,sizeof(flag));
        for(p=1;p<=i;++p)
          for(q=1;q<=maxq&&p*q<=i;++q){
            for(o=-1,k=1;k<=q;++k) o=(o==-1)?SG[i-p*k][j]:(o^SG[i-p*k][j]);
            if(o!=-1) flag[o]=true;
          }
        for(p=1;p<=j;++p)
          for(q=1;q<=maxq&&p*q<=j;++q){
            for(o=-1,k=1;k<=q;++k) o=(o==-1)?SG[i][j-p*k]:(o^SG[i][j-p*k]);
            if(o!=-1) flag[o]=true;
          }
        for(o=0;;++o)
          if(!flag[o]){
            SG[i][j]=o;
            break;
          }
      }
}
int main(){
    int i;
    scanf("%d",&T);
    while(T--){
        int now=0,o;
        scanf("%d%d",&n,&maxq);
        solve2();
        for(i=1;i<=n;++i){
            scanf("%d",&o);
            if(o) continue;
            int o2=0,o3=0;
            o=i;while(o%2==0) ++o2,o/=2;
            while(o%3==0) ++o3,o/=3;
            now^=SG[o2][o3];
        }
        if(now) printf("win\n");
        else printf("lose\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章