ABC274

ABCDEGの6完。ABC、思想的に早解きを要求してくるので、500を飛ばして600を通すみたいなことをしないといい順位取れない。 今回は運が良かった(難しいのがAなので大して損せず、Fが自分にはパッと見難しく、Gがなんかフロー)。とはいえ、Gが通ってなくても青パフォで、Eまで確実に解けるだけでも強かった。けど、Eまでに1時間かかっていて、簡単な問題しかなかったという感覚なので、楽しくはなかった。

A - Batting Average

簡単、たしかに簡単、でもABCのAにかけていい時間でそれは(俺は)できない。今にして思えば、分母が小さいので小数点第4位以下がちょうど0.0005になることはないんだなあ。

色々考えたしネットで検索もした。最終的に、普通にprintfで3桁だせば四捨五入に近い結果になることを知り(そりゃそうだ)、分母が小さいので10^-7とかを足しておけばそれで4が切り上がることはないし5は切り上がるのでOKということで提出してAC。5分近くかかった。

ユーザ解説の「制約が大きくても誤差無く出力する方法」いいね。こういうのをやりたかった。実際やると時間かかりそうだけど。

B - Line Sensor

打って変わって本当に簡単。答えのvectorを用意しておいて入力受け取りながら該当する場所をインクリメントしていく。

C - Ameba

1-indexedを強要されるような添え字が嫌。グラフのコードを貼ることも考えたが、落ち着いて考えるとDPみたいに順番に求めていける。入力を受け取りながら順にアメーバA_iの答え+1を配っていく。どう増えていくかの例を紙に書いたらイメージしやすくなった。

D - Robot Arms 2

やや身構えるが、ただのDPだ。bitsetでやると楽。座標にアームの長さを足しておいて、そこからはどっち向きかの選択で変化量が偶数に限られるので、偶数でない値になったらダメ、全部足してさえ片方でも負ならダメ。最初の選択は正の方向と決まっているのでそこは引き算しておく。あとはただのDPを2回、両方実現可能ならYes。わりとすぐ見えるけど、実装も含めると20分近くかかってるね。そういう意味で苦手。

E - Booster

TSPに毛が生えたような感じ。ブースターの個数M+1通りを持つのかなとか考えてると、単にN+MのTSPだと気づく(個数だけ持っても宝箱が空になった情報がないのでダメ)。N+Mが17以下でいつもの制約なの笑ってしまった(本当に笑ったか?)。原点からのコストでN+M箇所を初期化。貰うDPをするときに宝箱の部分のpopcountを見てブースターの数だけコストを半分にする。最後に、全部の街を訪れたケースについてブースターの数も考慮して原点に戻るコストを足して最小値を求める。さすがに実装が重かった。

F - Fishing

横軸を位置、縦軸を時間とした図を描く。少し考えて難しそうなのでGへ。

選ぶ魚が区間になるみたいな勘違いしてて終わった。ただ、2つの魚を選んで一緒に捕まえることができる時間帯は区間になり全部の組み合わせについて計算できるので、なんか解けそうではある。Twitterでイベントソートみたいなキーワードを見ていたので、考えているうちに思いついた。これlog付くんか。3秒だから通りそうではあるけど。いもす法みたいなイメージ。捕まえるときの左端を固定したときに何匹取れるかを全部調べる。実装しようと思ったけどかなり時間かかりそうで一旦あきらめた。

(追記)速度が同じかで場合分け。違うなら、(過去を含め)いつ同じ位置になるか調べ、そこから正の向きへAだけ離れる時刻も調べる。その早いほうから始まる区間を作りいもす法みたいにする。思ったほど複雑な式にはならなかった。過去からシミュレーションを始めて、時刻0以降の場所で最大値をとる。実装にはめちゃくちゃ時間がかかり、これは苦手。分数を大小比較するとき負の数を掛けたら不等号の向きが逆になるの忘れてはまった。

G - Security Camera 3

とりあえずACLを開く。2-SATも開いたけど、まあMaxFlow。ここで順位表を見ると、FGが同じくらいの難しさらしい。じゃあGに注力しよう。フローの計算量を確認すると、この問題だと辺の容量が1だけになりそうなので、マスの数だけ辺があっても大丈夫そう。カメラの左右は関係ない。縦か横の2種類を考えればいい。横だけでやるときと縦だけでやるときを考えると、そこで現れた幅1の長方形たちをできるだけ少ない個数使って空きマスを埋めるという問題になる。やはりフローっぽい。しばらく考えてわからないが、まあ雑に、めちゃくちゃ雑にそうなったらいいなというグラフを考えてみる。マスを辺として縦の長方形と横の長方形をつなぐ。最小化なので最小カットだろう。縦側と横側で分かれていて、真ん中の(マスに対応する)辺は容量∞っぽい(容量1じゃないけど強制的に同じ色にするみたいなのだからいいだろう(なんも知らんけど))。で、違う色になったところにコストが発生するのでなんかそれっぽい。実装しよう。頂点数を決める必要があって悩んだ。マス数*2くらいには収まるだろうが、極端に小さいときが不安なので適当に100を足す。その余裕を生かすために、ちょっと変則的だがH*Wからの2つを始点と終点にして、そこからのH*W+98個をカメラにする(今気づいたけど縦横両方必要なの忘れてた(まあ半分を超えることはなさそうだから足りてそうだけど))。まず横に見ていく。新しい区間が現れたらカメラ番号をインクリメントしてグラフに追加、マスをカメラとつなげる。それを縦横やってフローを流すとサンプルが通るので提出してAC。

流量が1ならいいのか。色が違ったらじゃなくて、Sの色からTの色への辺が容量にカウントされる(逆向きの辺ならカウントされない)。色々知らなかったり忘れてたりしてひどい。よくACしたな。横のカメラを選んだら縦のカメラはどうでもいいし、選ばなかったら縦のを選ぶ必要がある。最小カットで解けていそう。上手くできてるなあ。なんで通った。まあめっちゃありがちなフローだったからな。これ以外書きようがないというか。なんか正解の位置に落とし穴(これ古いコンピュータ将棋用語か?AHCでいうと山登り法の山のこと)があってくれた。

(追記)解説の実装例がシンプルで良い。