kmjp's blog

競技プログラミング参加記です

yukicoder : No.946 箱箱箱

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;
	
	
}

まとめ

わりと手間取った。