ABC143

5完。終了10分前37.0度。体調が不安だったので風呂に入らなかった。おかげでいい感じに解き進めることができた。結果がよかったわけではないがコンテスト中は楽しめた。

A - Curtain

max(a - b * 2, 0)。カーテンってひだがあるから「長さとは」って感じだよなと思いながら解いた。

B - TAKOYAKI FESTIVAL 2019

「これ絶対O(N)解法あるだろ」と思いながら愚直を書くのは微かな悲しさがある。

C - Slimes

簡単すぎて不安になりながら書いた。実装は、最近パターン化してる書き方できれいに書けたので満足。(解説PDFを見て)std::unique気づかなかったあああ!!使うかはともかくこれ気づけないのは。必ずしもソートと一緒に使うわけじゃないって知ってはいるけど、知ってるだけなのでこういうときに出てこないんだよなあ。

D - Triangles

3乗が通らなそうなのを確認。少し考えてから、あまりよくないけど制約から2乗の解法を探して2つの棒を固定することを思いつく。三角形になるというのは、もう1本の棒の長さがある範囲に収まるということ。幸いLの範囲は狭く、これは簡単に解けそうだ(実装が簡単とは言っていない)。累積和を使う(二分探索も思いついたがTLEを気にする時間が無駄(AtCoderでこれがTLEするわけないけど))が、範囲外アクセスをしないよう気をつけないといけない(長さ1500以下の本数というクエリが来たら、長さ1000以下の本数と同じなのでそれを返す)。選んだ2本がその範囲の中に入っていたら引き算しないといけない。とりあえずサンプルで様子をみて、3倍っぽいので3で割る(やる気なさすぎだろ!)。順番でも区別したら6倍になるが、自分のコードでは1つの大小関係だけ固定してるから半分になってる(と逆算したほうが思考を節約できるという当初からの読み通りですね(ほんとに考えるの疲れる))。できそうだという見通しはすぐに立つが、これを素早く実装するのは無理だなあ。(解説PDFを読んで)長いほうから固定するのいいな。いや探索する範囲が動的なのも発想としてはあったけどなるほどそういう。

E - Travel by Car

ただ最短距離を答えるだけならワーシャルフロイドでいけるなとまず思う。さて、距離とは。この問題設定は距離なのか?何であればワーシャルフロイドが使える?何であればダイクストラが使える?何もわからない、みじめな自分。まあ考える。ちょっと逆から考えてみるか。タンクの容量が100で、燃料0でゴールして、距離51なら燃料を51まで増やす。次にまた距離51なら空にしてから51まで増やす。かなり考えづらいが、いけそうに思える。そうすると、逆じゃなくてもよさそうだと気づく。ダイクストラ的に考えると、例えば「3回の補給と距離51の移動」のような情報を持てば更新していけそう。その情報もlong longの値として表現できるし、比較もそのままできる。さて、できればワーシャルフロイドでやりたい。ライブラリを漁るとなんかあったのでそれを持ってくる。メンバ変数の初期化順がアレだ。これだから普段使わないやつは。さて、2つを結合する処理を書く。書こうとして、このタンク容量でそもそも移動できないやつをINFにすることに気づく。けっこう複雑な問題。下位32bitに走行距離、上位32bitに補給回数とする。繰り上げみたいな感じで。移動距離は、最初のLまでなら0回補給で行けるので、Lを超えたら繰り上げという変則的な処理。サンプル合わないので気づいたけど、これダイクストラじゃないとダメでは。2つの経路を合成できないよ。当時は深く考えてなかったが、こう、ダイクストラの1個ずつ伸ばしていく更新方法ならできるやつに見えた。ダイクストラは、こっちのコードだと辺が多いグラフで定数倍が遅くなるとわかっているがさすがに使い慣れたほうを使う。コードを移植する。移動できない辺はそもそも追加しないことにする。N^2個の距離は別の配列を用意することにした(このへんもけっこう悩む)。なかなかサンプルが合わず困っていたが、そもそも距離の足し算が全然違ってる。繰り上げじゃないじゃんw(酷い)(余った燃料は意味がない)。いみふなミスを直すとサンプルが通るので一呼吸おいて提出。いやあ時間かかった。発想としてはけっこう早い段階で出てるのに。(解説PDFを読んで)何これ。やばっ。

F - Distinct Numbers

個数だけが重要だ。親切にもA_iはN以下だし。個数を数えたらソートしてしまってよい。なんか調和級数でO(NlogN)っぽい気もするがどうか。最初は上手く貪欲にK個を取っていく方法を見つけてそこから解法への道をうかがうという方針だった。多いのから順に取るの繰り返せばとりあえずOKっぽいがそれ以上のアイデアは出ない。しばらくして、多いK個を見てそれ以外のやつでそこを埋めるというのを思いつく。それ以外のやつの個数は累積和でわかるし情報は個数だけでいいから簡単(これも実際の実装を思うとそこだけでも時間内には無理だろうなと思った)。問題は埋め方だが、階段みたいになってる形はKによらず変わらないので、なんか難しそうだけどできそうではある。もう少し考えて、階段の空いてるとこの面積を事前計算しておいて、どこまで埋めるかを決めればその面積からちょっと掛け算で面積補正すればO(1)でできそうだから二分探索できそうと気づく。この時点で残り10分なので、諦めてしまった。解法が見えてると逆に無理なのが確定する感じ(実際は解けてない可能性も高いし、10分で書ける解法が存在する可能性も(低いけど)ある)。まあその方針で残り時間も考えてたけど。体温測ったり、ツイートが浮かんできたりね。