ABC315

6完。たまには橙パフォ取りたいねえ。なんか今日はそれほど疲れていない。

A - tcdr

問題文からコピペしようと考えて、カンマが入っていたのでそこで止まってしまった。カンマとスペースを消して"aeiou"とすればよい。2分超えてるのはよくないけど、まあA問題はロスしてもその程度の時間なので気にする必要はない。

B - The Middle Day

1年がS日とする。S日にそれぞれ0からS-1までの番号を付ける。番号がfloor(S/2)の日が何月何日か求めたい。floor(S/2)から、月の日数を順に引いていく。0以上その月の日数未満になったら答えを(1-indexedに直して)出力して終わり。考察が難しくて時間かかってしまった。面白かった。

C - Flavors

美味しさで降順ソートして最初の2個を同じ味として満足度を計算する(違う味でもs+t/2の満足度を得る権利があるとして答えは変わらない)。あとは、違う味の2個の美味しさの和の最大値を求めるだけ。これが意外と難しい。そもそも美味しさが最大のものに違う味があればそれでいいが、そうでないときは降順に見て初めてあった違う味のものと合わせればいい?今考えるとよさそうだが、なかなか確信が持てず、楽な実装も見えず、結局unordered_mapで味毎に美味しさの最大値を求めることを思いついて、やや牛刀みはあるがすっきり解けているので採用した。味は1種類かもしれないことに注意する。

解説のコードが全然読めないと思ったら、味が1以上N以下なの気づいてなかった。

D - Magical Cookies

なんかARCが始まった。「2枚以上」という条件もあって、シミュレーションするしかない気がする。各行各列にどの文字が何個あるか数えておく。ある行で'a'が列の残り数と同じ個数あったらその行を消す。行を消したら列の残り数を減らす。実装していて気づいたが、各列の'a'の個数も減らさないといけない。方針ミスったかと思ったが、それぞれの文字について各列から何個消されたかを持っておけばリカバリーできそう(こういう流れは不安だけどな)。サンプルが合わず、2個以上の条件を忘れていたが、それを実装しても行と列を同時に、消さずに印を付ける必要があった。行の残り数と列から各文字が何個消されたかをバックアップしてから処理することでなんとかAC。

E - Prerequisites

一転してトポロジカルソートするだけかよ。と思ったらサンプル全く合わず、全部出力したらそりゃだめだ。ちょっと迷ったけど、逆に辺張ってDFSで行ける場所を求めて、トポロジカル順に頂点を見て行ける場所だったら答えのvectorに加えるという処理でAC。時間がかかってしまった。

DFSの帰りがけ順でいいってマジ?言われても正しいかどうかわからなかったけど、確かに帰りがけには必要な本を全部読んである。DFS版のトポロジカルソートを最近全く使ってなかったなあ。BFS版じゃないとできない処理が多くて、そっちだけでいいと思っていたふしがある。

F - Shortcuts

巡回セールスマンを10^4で!?と思ったがよく読むと順番は固定されていた。よかった。飛ばさず全部回ってもsqrt(2)*10^8以下には収まるので、Cは28まで考えればいい。きりよく30未満として実装した。こういう見積もりが出てくる問題好き。あとは普通にDP。入力を受け取りながらやるけど、よくあるN回の遷移ではなく、N-1回なので最初だけforの外で入力を受け取ることになった(実装前に気づきたい)。

G - Ai + Bj + Ck = X (1 <= i, j, k <= N)

AiがA_iに見えてしまう。文脈からわかっているのにね。さて、とらえどころがない。i,j,kが実数の方程式として見れば、3次元空間内の平面になり、その平面上の格子点の数を求める問題になる。ということは、kをN通り固定すれば2次元の問題になる。これは解けそうに見える。floor_sumとピックの定理で行けるかと思ったが、端がだめだ。普通にextgcdで整数解が求まって、そこから範囲内の解の個数もわかりそうだが、普通にやるとオーバーフローするのと、そもそも境界を合わせるのがかなり大変そう。

(追記)AとBが互いに素な問題に帰着させておく。S:=X-C*kとしてA*i+B*j=Sの解の個数を高速に求めたい。i,jの範囲を無視して解を一つ求めるとき、A*x+B*y=1の両辺をS倍するとオーバーフローするので、まずBで稼いであまりをAとBで調節する。次にA側を範囲内で最も小さい係数にする。それでもB側が0以下なら解なし。ここから難しかった。次にB側をN以下に持ってくる(もしNより大きかったら)。A側がNより大きくなったら解なし。そしたら、A側がNより大きくなるまでとB側が0以下になるまでをそれぞれカウントして小さいほうが答え。これを足していく。