Google Code Jam 2019 Qualification Round : Dat Bae

問題. Dat Bae

 N 台のマシンがあり, 0 から  N - 1 までの番号付がなされている.それらのマシンの内  B 台が壊れている.次で定義するマスタとの間のインタラクティブな通信を高々  F 回行いどのマシンが壊れているかを特定せよ.
インタラクティブな通信とは,長さ  N の 0 と 1 からなるビット列  s をマスターへ送ると,マスターから  N 台の各マシンに1ビットが送信される. i 番目のマシンはマスターから  s_i を受信する.壊れていないマシンは受信したビットをマスターへ送信して,壊れているマシンは何も送信しない.マスターは各コンピュータから受信した1ビットをマシンの番号の昇順に並べて,その長さ  N - B のビット列を送り返す.

制約 2 \le N \le 1024,  1 \le B \le \min\{15, N - 1\},  F = 5

解法

マスタに送信する1回目のビット列  s を構成する. s を左から順番にブロックサイズが  B となるように分割する.各ブロック内のビットが同じになるように,左のブロックから順番に 1 と 0 を繰返し割り当てる. s をマスタへ送信して, r を受信する. r を見るとどのブロックにいくつ壊れていないマシンが存在するかが分かるので,後は各ブロック内を同様に長さ  B / 2, B / 2^2, B / 2^3, \ldots と分割してマスタにビット列を送信することによって区間内の壊れていないマシン数が分かる.
初めから  N / 2, N / 2^2, N / 2^3, \ldots と分割する方法だと通信回数が  \log N となり制約を満たさない.ここで, B の数が小さいことに着目して初めは長さ  B のブロックに分割すると, B のサイズは高々  15 なので  log 15 \sim 4 回の通信で答えを求めることができる.

 

ローカルでのテスト方法

ローカル環境でのテストのために testing_tool.py というPython言語で書かれたプログラムが与えられる.作成したプログラムの実行ファイルを my_solution として次を実行するとテストが行える.
testing_tool.py は引数を1つ取り今回は 0 とする.mkfifo コマンドで名前付きパイプ FIFO を作成する.そして,python3 testing_tool.py 0 への標準入力を FIFO から,標準出力をパイプ | を用いて実行ファイル ./my_solution への標準入力へとリンクしている.また,./my_solution の標準出力を FIFO へリンクしている.このようにすることでプロセス間通信が行えて,インタラクティブ問題のテストが行える.

$ mkfifo FIFO  # 名前付きパイプを作成
$ python3 testing_tool.py 0  < FIFO | ./my_solution > FIFO  # テストを実行

 
他の方法として,nico_shindanninさんのツイートが参考になる.

 

インタラクティブ問題を初めて解いたのでデバッグが大変だった.
GCJ は実装が大変(他の問題は多倍長整数が要求されたりと).
Tシャツもらいたいな.