ABC350

6完。マスターズの表彰式が終わった18:49頃に離脱。19:00の電車に乗り(会場が地下鉄と直結している)、無事ABCに間に合った。

レーティングは下がったものの、FGに1時間を残し、Fも迷走した中で時間をかけてしとめる立ち回り。ゲームメイクがよかった。

A - Past ABCs

ABCの略称が辞書順に並んでいることを利用する。辞書順で"ABC350"より小さければおおむねYes。ABC316が例外。まさかA問題でそんなことしないだろうと思っていたけど、問題文を読み直したらABC000も例外だった。やばすぎる。

B - Dentist Aoki

治療するたび1をxorする。最後に全部の穴を数える。こういう(青コーダーにとって)軽いBは久しぶりだ。

C - Sort

b[a[i]] = i; のようにして、各数がどこにあるかを持っておく。左から順にswapしていけばよさそう。自分よりも右の要素としか交換しない(既に左には、ここにあるべき要素より小さいものしかない)ので、大小関係は大丈夫。更に、bを更新しなくてもサンプルは通る。これが本当かどうかを考えるが、4 2 3 5 1という例で撃墜できた。ということでbの更新を書く。どっちを先に更新すると壊れるとか面倒なので、交換するインデックスを変数に保存しておいて、aをswapし、bをaを使ってswapした(aはswap済みだが別に入れ替わっていても同じこと)。けっこうきつい実装だった。

D - New Friends

考えていくと、UnionFindだろってなる。友達関係を無向辺として連結成分内は全員友達同士になれる(と思う)。

解説の証明見て、パスをとるのなるほど~ってなった。

E - Toward 0

こういうの(ループがある期待値)相対的に得意だと思ってたけど違ったかも。メモ化再帰。割る数が2,3,5の組み合わせしかなくて割れる回数が高々60回だからその3乗としても間に合う。証明できるわけではないが、さすがにこういうのは何回も出題されて慣れている。あとは再帰を使って計算するだけだが、Y円払う操作で1が出たときY円だけ払って状況が変わらないのが難しい。感覚ではわからんので数式で求める。最初サンプル合わなかったのは、Yを2箇所で足してたからだった。

解説の計算量の説明、切り捨て除算2回をまとめられるの確かにそうなんだろうけど(明らかに証明できそうだし実際証明できたけど)、感覚としてわかってないな。

(追記)Y円払う操作をしたときの期待値を求めるとき、X円払う操作は考えなくていいというのが感覚的にわからなかった。それまでに払った金額がゲーム内容に影響しないので、サイコロで1が出たら最善手も変わらない。ここからが難しいのだが、だから同じ状況で違う操作をしないとしてよい。そういう制約を加えた問題を解けばいいので、X円払う操作は考えなくていい。

F - Transpose

まず愚直(stackで対応する括弧の位置はわかるようにしておく)を書いてサンプルが通ることを確認。きれいではないが、平方分割でできそうだと思う。小さい区間は愚直にやり、大きい区間は名前を付けて1文字に置き換える。反転したかの情報を持っておく。そのためにcharではなくintで処理する。復元は順番に再帰的に。大きい区間をちゃんと縮めるために別の列へコピーしながら。この辺りでさすがにおかしいと思い、正面からの解法を探した。まず、大文字小文字の反転は括弧の深さの偶奇で決まるので簡単に前処理できる。あとはreverse処理だけだが、これは再帰でできそうだ。括弧の相手を前計算しておき、向きを反転させながら順に文字を答えのstringへ追加していく。再帰する部分以外は1文字ずつ処理して大丈夫、再帰するところは対応する括弧へジャンプしてO(1)で済ますようにする。これで計算量は大丈夫。答えが合ってる確信はなかったけどサンプル通ったしさすがにという感じでAC。

G - Mediator

メモリの制約がきついんだね。Nがわりと小さいね。隣の頂点のリストを持って共通部分、bitsetでできそうだね。ビット位置を求める機能なさそうだから自作しよう。提出してMLE。記憶力~。