この記事は 解説 Advent Calendar 2017の24日目の記事です。
以下のコンテストの解説です。 www.hackerrank.com
はじめに
競プロ!!Advent Calendarのこの記事 (競プロにおけるNim、Grundy数とNimK - かっさのなにか)に 触発されて書きました(というか解いてないことを思い出した)。
以下ではNim, grundy数などの知識を前提としています。
全く知識がない、あるいは不安な方は上の記事を読んでから解く and/or 解説を読むことを推奨します。
またxorをで表します。
特に記述がなければ、先手(プレイヤー1)と後手(プレイヤー2)が交互に手を打つゲームとし、
どちらのプレイヤーが勝つか出力する問題と思ってください。
Game of Stones
概要
Programming Problems and Competitions :: HackerRank
山に石が個ある。
プレイヤーは山から
個いずれかだけ取り除ける。
取り除くことができなくなったプレイヤーの負けである。
解法
メモ化再帰。
Tower Breakers
概要
Programming Problems and Competitions :: HackerRank
それぞれに石が個ある山が
山ある。
プレイヤーは一つの山に石が
個あるとき、
個に減らすことができる。ただし
は
を割り切れなければならない。
解法
のときは明らかに後手勝ち。
とする。
が偶数ならば後手は先手と全く同じように操作ができるから後手勝ち。
が奇数ならば先手が最初に
つの山を
にすれば、上と同じ戦略が取れるから先手勝ち。
A Chessboard Game
概要
Programming Problems and Competitions :: HackerRank
のチェス盤に石が
つ置いてある。
プレイヤーは
にある石
つを
の
いずれかに移動させる。ただし盤面外に移動させることはできない。
手を打つことができなったプレイヤーの負けである。
解法
メモ化再帰。
Nim Game
普通のNimなので略。
Misère Nim
概要
Programming Problems and Competitions :: HackerRank
山のNimをする。ただし普通のNimと違うところは
最後に石を取った人が負け (手が打てなくなったプレイヤーが勝ち)
という点である。
解法
まずすべての山が1個の石からなるケースを考える。 このときは山の数が偶数なら先手勝ち、奇数なら後手勝ちである。
それ以外のとき、を(普通のNimと同じように)すべての山の石の個数の
xorをとったものして
のとき、かつそのときに限り、後手勝ちであることを示す。
今、先手番でとし、先手が手を打つことでこれが
になったとする。
このとき、後手番ですべての山の石がとなることは無いことが分かる。
もしそうなったとすると、仮定から先手が選んだ山以外の石の数はすべて
であり、
先手が選んだ山はもともと
個より多くの石があったことが分かる。
しかしこのような状況は
の下では明らかに起こりえない。
これより、後手番では少なくともつの山は
個より多い石がある。
石が
個より多い山がちょうど
つあるときは、その山を
か
に減らすことで、
山の数が奇数となるようにすべての山を
にする
ことができるので後手が勝つ。
そのような山が
つより多くあると、次の先手番ではすべての山が1個の石からなることはない。
従って通常のNimと同じようにして
となるように後手は手を打つことができ、
帰納的に後手勝ちであることがわかる。
逆に先手番でとすると、上の後手番の議論をそのまま適用できるので先手勝ちである。
よってすべての山が個の石である場合を例外扱いすることで、普通のNimと同じように解ける。
解説だと全部のときだけ場合分けすればいいとしか書いてないし、
それが正しそうな理由もよく分からなかった。
自分は実験してなんとなく規則性を見つけて適当に投げた。
実験せずに気付けるかと言われると微妙。
Nimble Game
概要
Programming Problems and Competitions :: HackerRank
個の箱が一列に並んでいて、
と番号が付いている。
各箱には石が
個入っており、プレイヤーは
番目の箱にある石
つを箱
に移すことができる。
先に手を打つことができなくなったプレイヤーの負けである。
解法
位置にある石はそれより小さい
のどこへでも動かせる。
これはNimの
つの山にある石の個数が
個であるときの状況とちょうど対応している。
よって
が
なら後手勝ちである。
Poker Nim
概要
Programming Problems and Competitions :: HackerRank
山にそれぞれ
個石がある。
プレイヤーは各ターンで
つの山から
個以上の石を取り除くか、あるいは追加することができる。
ただし、石を追加できる回数は各プレイヤー、各山に対して高々
回までである(個数は任意)。
最後の石を取り除いたほうが勝ちである。
解法
石を追加しないNimと全く同じ結果になる。
つまり、のとき、かつそのときに限り、後手必勝となる。
のときは先手が石を取り除こうが追加しようが、後手は先手と同じことをすればNim和は
になる。
また石の追加は高々
回までしかできず、必ず有限回で終わるので後手必勝。
のときは適当に石を取り除いて
の状態に持っていけるので先手必勝である。
Tower Breakers, Revisited!
概要
Programming Problems and Competitions :: HackerRank
山にそれぞれ
個石がある。
プレイヤーは
つの山にある
個の石を
まで減らすことができる。ただし
は
の
約数でなければならない。
最後の石を取り除いたほうが勝ちである。
解法
山がつで
個石があるとする。
このときのgrundy数がどうなるか考える。
のある約数
のgrundy数を
とすると、
の任意の約数
にも
から遷移できるので、
のgrundy数
は少なくとも
以上である。
これを
のすべての約数にわたって考えれば
となる。
よくよく考えるとこれはの重複を含めた素因数の個数(例えば
なら
)と一致することがわかる
(素因数
で
を割ったものならどれでも最大になるため)
ので、各
のこれを調べて最後にそれらのNim和をとればよい。
Tower Breakers, Again!
概要
Programming Problems and Competitions :: HackerRank
山にそれぞれ
個石がある。
プレイヤーは
つの山にある
個の石を、
個の石からなる
個の山に分けることができる。
ただし
でなければならない。
最後の石を取り除いたほうが勝ちである。
解法
基本的につ前の問題と同じで重複を含めた素因数の個数がgrundy数となる。
ただし
を素因数にもつときは一度だけしか数えない(
のグランディ数が
となるから)。
Chessboard Game, Again!
概要
Programming Problems and Competitions :: HackerRank
のチェス盤にいくつか石が置いてある。
つのマスに石が複数置いてあっても良い。
プレイヤーは
にある石
つを
の
いずれかに移動させる。ただし盤面外に移動させることはできない。
手を打つことができなったプレイヤーの負けである。
解法
素直にgrundy数を計算すれば良い。
盤面がで、ありうる遷移が高々
なので愚直に計算しても十分に間に合う。
位置
から動かせる手
について
が成り立つから、
が小さいものから順に計算することができる。
Digits Square Board
概要
Programming Problems and Competitions :: HackerRank
のマスに整数
が書かれている。
プレイヤーは盤面の面積が
より大きく、かつ素数でないような数字が少なくとも
つ書かれているとき、
盤面を水平方向か垂直方向に
つに分割することができる。
手を打つことができなくなったプレイヤーの負けである。
解法
素直にgrundy数を計算すれば良い。
でメモ化再帰する。
素数でないものが部分長方形に入っているかを累積和で前計算しておけば、盤面が分割できるかどうかは
で判定できる。
上の状態が
あり、各状態からの分割方法は
あるので、
全体で
で計算できる。
Fun Game
概要
Programming Problems and Competitions :: HackerRank
長さの
つの数列
がある。
プレイヤー
は
から、プレイヤー
は
から交互に数字を選んでいく。
ただし
がすでに選ばれていたら
を選ぶことができず逆も同様。
なのでちょうど
回の操作でゲームは終わる。
各プレイヤーが選んだ数の総和を計算し、大きい方が勝ち、同じなら引き分けである。
解法
この手のつの数列から片方を選ぶみたいな問題は適当な評価値を決めて、
大きい方から選んだりdpしたりすることが多い気がするのでそうする。
このゲームは次のようなゲームに置き換えられる。
- プレイヤー
は初期点として
を持っている。
- 数列
がある。
- プレイヤー
は
から数字を一つ消すことができ、プレイヤー
は選んだ数だけプレイヤー
の点数を減らせる。
- 最後にプレイヤー
の点数が正ならばプレイヤー
の勝ち、
なら引き分け、負ならプレイヤー
の勝ち。
なのでを計算、ソートして、数字が大きいものから順番に消す、点数を減らすことを交互にすればよい。
Powers Game
概要
Programming Problems and Competitions :: HackerRank
文字列がある。
プレイヤーは交互に
を
か
のどちらかに
つずつ書き換える。
最後にすべての
が無くなったら数式を計算し、
で割りきれたら後手勝ち、そうでなければ先手勝ち。
解法
だけを気にすればいいから、現れる数字は実質
だけとみなせる。
また、
なるものがあれば、お互いに打ち消すように手を指すことができる
(片方が
に書き換えたらもう片方は
に変える)ので、奇数個あるものだけ着目すれば良い。
あとは
のように
をbitとして使いメモ化再帰で解ける。
なので
から順番に前計算しておけば良い。
Deforestation
Programming Problems and Competitions :: HackerRank
既出。同じ問題がhttps://beta.atcoder.jp/contests/agc017/tasks/agc017_dにある。 ハッケンブッシュ(Hackenbush)というゲームがあってそれの特殊な形である。
Tower Breakers - The Final Battle
概要
Programming Problems and Competitions :: HackerRank
個の石がある。
となるまでプレイヤーは以下の操作を交互にする。
- プレイヤー
は
となるように自由に石を分割する。
- プレイヤー
はこの中から
番目の山を選び、
としてゲームを続ける。このときコイン
枚を得る。
プレイヤーはプレイヤー
が得られるコインの枚数を最小化、プレイヤー
は最大化しようとする。
このとき最終的に得られるコインの枚数はいくらか。
解法
小さいケースで実験するとがある程度大きくなっても答えは大きくならないと予想ができる。
そこでとする。
明らかに
は単調増加になるから、
となるような最大の
が求める答えである。
番目の山を選ぶとコインを
払うことになるから、
となる。
で
となるから愚直に計算しても実行時間は十分間に合う。