kmjp's blog

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

yukicoder : No.2666 Decreasing Modulo Nim

ちょっと自信なかったけど通った。
https://yukicoder.me/problems/no/2666

問題

通常のNimに、正整数Mを用いた変則Nimを行う。
通常のNimとの違いは、取り除く石の数をMで割った余りを取ったとき、前の手番以下の値になるようにしなければならない点である。

Nimの初期状態を示す数列AとMが与えられたとき、最適手を取るときの勝者は誰か。

解法

初手でMの倍数の石を取り除く場合、以後もMの倍数しか石を取れなくなる。
よって、B[i]=floor(A[i]/M)として作られたBにおいて、先手必勝の場合、Aでも先手必勝である。

そうでない場合、Bが先手必勝になるような形に崩してしまうと良くない。
C[i]=A[i]%Mとして作る数列Cにおいて通常のNimを行うと、それがAにおける勝者/敗者となる。

int N,M,A[202020];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>M;
	int nim=0,nim2=0;
	FOR(i,N) {
		cin>>A[i];
		nim^=A[i]/M;
		A[i]%=M;
		nim2^=A[i];
	}
	
	if(nim||nim2) {
		cout<<"Alice"<<endl;
	}
	else {
		cout<<"Bob"<<endl;
	}
	
}

まとめ

最初まじめにGrundy数出力してみてもよく規則性がわからなかった。