ちょっと自信なかったけど通った。
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数出力してみてもよく規則性がわからなかった。