Grundy数の理解を改めて問う問題。
https://yukicoder.me/problems/no/946
問題
N個の箱が積み重なっており、上からA[i]個のボールが入っていることがわかっている。
これらを使いNimの変形ゲームを行う。
通常のNimと異なり、各自の手番では下記のいずれかを行える。
- 開いている箱を1つ選び、1個以上のボールを取り除く。
- 積み重なった箱のうち、上から連続するいくつかを下ろし開ける。
最適手を取ったとき勝者はいくつか。
解法
f(n) := まだ詰まれた箱がn個ある状態のGrundy数
とし、f(N)=0かどうかを判定しよう。
f(n)を考える際、他に開いた箱はないので、箱を開けるしか選択肢がない。
明けた後の状態のGrundy数を求めよう。
i個箱を開けた場合、それらのA[b]のxorと、f(n-i)のxorを取った状態が新たなGrundy数となる。
あとは遷移先のGrundy数に関するmexを求めよう。
int N; ll A[2020]; int memo[2020]; int grundy(int cur) { if(cur==N) return 0; if(memo[cur]>=0) return memo[cur]; set<int> S; int x=0; for(int take=1;cur+take<=N;take++) { x^=A[cur+take-1]; S.insert(x^grundy(cur+take)); } x=0; while(S.count(x)) x++; return memo[cur]=x; } void solve() { int i,j,k,l,r,x,y; string s; cin>>N; FOR(i,N) { cin>>A[i]; } MINUS(memo); if(grundy(0)==0) cout<<"Takanashi"<<endl; else cout<<"Takahashi"<<endl; }
まとめ
わりと手間取った。