ABC269

6完。今朝から体調悪かったけどコンテスト前には普通に戻って、コンテスト中はいいパフォーマンスが出せた。順位は普通だったが。

A - Anyway Takahashi

式をコピペすると、×はわかってたけど−も半角じゃないので直す必要があった。Takahashiもコピペしてきて、ギリギリ1分切り(えらい)。

B - Rectangle Detection

けっこう難しいと思うけど、こういうのはABCのBとしていいと思う。順番に1行ずつ見ていって、最初の'#'と最後の'#'で位置をメモすればいい。最初というのは、メモする変数を答えとしてありえない数で初期化しておくことで最初かどうかを判定する。最後は、'#'が来るたびに上書きするだけでいい。

C - Submask

計算量が3^Nになる例のコードを(内側だけ)貼る。

D - Do use hexagon grid

六角形怖いけど、何と隣接するか書いてあるので六角形のことは忘れていい。Nが小さいので2003*2003のサイズでUnionFindできる(16MB一気に確保するだけなら高速で、その後の処理も大して遅くならない)。マスを塗ったかのフラグも持つ。答えの変数をNで初期化し、あとは隣接する位置が塗ってあればつなげようとして、未結合のものを結合するたびに答えの変数をデクリメントする。

E - Last Rook

ABCDがB問題と同じ形式で良い。10^6通りの答えが考えられるのに質問は20回と少ない。これは二分探索が見えやすい。内容的には簡単だが、実装はちゃんとやる必要がある。行と列で別々にやる。最初[0, N)に答えがある状態から始まって、前半分でクエリを出して幅よりルークの個数が少ないなら前半分にある。区間の長さは1回の質問で、今の区間の長さ以上の最小の2冪の半分以下になるので大丈夫。区間の長さが1より大きい間続ける。区間の長さが1ならそこにルークがある。手でテストして、N=1は(制約外だけど)大丈夫。N=5でやったとき、行と列で質問を変えてなかった(ABとCDを入れ替える)ことに気づき直す。運よくAC。

F - Numbered Checker

嫌な見た目。書かれている数の偶奇ではなかったので一安心。横方向の和は等差数列なので求まるが、その和を縦方向に見ても等差数列になっているので、これは一応簡単。しかし実装が怖い。Gを少し考えて、解けないので戻ってきた。横方向にここからここまでの和を求める関数を書く。半開区間ではなく閉区間を使う。最初の位置は、奇数なら1進める。最後の位置は、奇数なら1戻す。そしたらそこに書かれている数はそのまま求まるので、最初と最後の数の和と0でない数の個数から和が求まる(0でない数が0個のときも正しく求まる)。この関数を使って、一番上の行、その次の行、一番下の行、その前の行の和を求める。ここからは、AとBの偶奇が一致するかで場合分け。等差数列になるのでまた同様の計算をする。こちらも、個数が0でも正しく求まる。コード量は多いものの、意外とシンプルに書けた。

G - Reversible Cards 2

min(A_i, B_i)は必ず足されるので引いておく(引いた数の和は持っておく)。少なくとも片方が0になる。とりあえず愚直DPでサンプル通すところまではやった。平方分割して半分全列挙みたいにできないかなとか思ってた。裏表の差が全部1なら簡単なので、数が小さいとき上手くできないかなと思ったけど、小さいとはいえナップサックだからなあ。100以下とかでは厳しそう。あとはマージしてくやつかなあ。Gにあと10分多く残したかったと最初は思っていたが、全然だった。

(追記)思い切ってB_i-A_iだけ使えばいいね。そして、その値がO(sqrt(M))種類しかないというのはなるほど。これは気づきたいねえ。DP部分は、自分の愚直は配っていたが、貰うようにすればin-placeでできた。短時間で書き切ることを目指していたとはいえ、こんな基本的なDPで気づかないのは力不足。しばらく考えるとSWAGで貰うDPもできそうではあるが実装は重そう。解説にあった2冪と半端に分割する方法がすごくて、実装も負荷が少なそうなのでこれで実装した。B_i-A_iが負のときの和とAの和を使うのだが、かなり混乱した。