kmjp's blog

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

yukicoder : No.669 対決!!! 飲み比べ

ちょっと間が空きました。
https://yukicoder.me/problems/no/669

問題

Nimの変形問題。
山にある石を任意個数でなく1~Kの間でのみ取り除くことができるとき、勝者はどちらか。

解法

良くあるGrundy数の計算をまともにやると、Grundy数計算にO(K*(山の石の最大数))程度かかりTLEする。
小さめの数字で試したり、もしくは再帰的に考えると石の個数Xの山のGrundy数はX % (K+1)になるので、あとはこれをもとにいわゆるNimを解くだけ。
以下のコードは10000程度までは愚直にGrundy数を求めている。

int N,K;
int A[1010];
int gr[1010100];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>K;
	for(i=1;i<=10000;i++) {
		set<int> S;
		for(j=1;j<=min(K,i);j++) S.insert(gr[i-j]);
		while(S.count(gr[i])) gr[i]++;
	}
	for(i=10001;i<=1000000;i++) gr[i]=gr[i-(K+1)];
	
	int nim=0;
	FOR(i,N) {
		cin>>x;
		nim^=gr[x];
	}
	if(nim==0) cout<<"NO"<<endl;
	else cout<<"YES"<<endl;
	
}

まとめ

実装は軽いけど、Grundy数の問題を★3未満にするにはちょっと戸惑うね。