ABC223

7完、Hは覗いただけ。こどふぉがあったため上位陣の参加が少なく、そこで橙パフォ相当のパフォーマンス(回りくどい)を出したため近年ではありえない順位になった(たぶん青がratedになるコンテストでの最高順位更新)。

A - Exact Price

かなり難しい。問題文を何度も読んだ。半分に切った100円硬貨とかも考えた(それは100円硬貨ではない)。

B - String Shifting

rotateしたものを全部vectorに突っ込んでソート。

C - Doukasen

まず二分探索が浮かぶが、さすがにやらない。ただ、かなり難しい。こんがらがる。まず全体を走り抜ける時間を求める。その半分以上に到達したら1個戻って、半分になるまでにその導火線のどこまで行くかを計算する。明らかに簡単だけど、瞬殺する力はなかった。

(解説の実装を見て)なるほどこう書けば楽なのかあ。

D - Restricted Permutation

トポロジカルソート。最近自分で書いてない(中身の理解が怪しい)のでドキドキする。ライブラリからBFSでやるやつを持ってくる。まずそれを読んでおく。入次数が0のものは先頭になれる。使った頂点からの辺を削除していって入次数が0になったらキューに追加。-1になるのは、ループが残るとき(トポロジカルソートできるかの判定すらしばらく「どうやるんだろー」ってなってた)。先頭になれるものは列挙できているので、最小のものを選ぶ。ここは簡単にわかるが、次からがよくわからない。まあ自分がよくわかってなかっただけ。先頭を決めたときのその次に来れる候補も新たな入次数0が追加されるだけなので最小を選んでいけばいい。つまり、キューを優先度付きキューにする。これはいい問題だ。

E - Placing Rectangles

よくわからん問題。どれかの長方形が角を取るとしていいかすらわからん。しばらく時間をおくと、縦か横に3分割する方法の他にそれほどパターンがなさそうなのが見えてくる。他にはT字に分割するやつ。これ以前のAtCoderであったな(ARC074Cらしいがそんな前だったか)。証明は全くできないけど、全パターンループで回してチェックする。

(追記)解説にちゃんと証明が書いてあって、良い。これだよ解説に求めるものは。自分の理解は「なんとなく正しそう」くらいまでしか行かないけど。

F - Parenthesis Checking

正しい括弧列の判定は、開きと閉じが同じ個数でかつ累積個数で常に開きが少なくないこと。セグ木とかでできそう。クエリのスワップは、累積和がその区間だけ2変わる。つまり、累積和を持って点取得と区間min取得と区間加算ができればよい。思ったよりしんどそうだが、遅延セグ木でたぶんできる。久しぶりだから不安。やってみるとすんなり書けた(内部の理解は怪しい)。対象が累積和なので添え字が1ずれたりしてとにかく混乱する。こういうのそこそこの時間でそこそこの精度で書けるのは強い(最近強くなった部分だと思う)(ほんとは確信を持って書きたいけど)。

(追記)解説見て、ただのセグ木でいいと知る。なるほど実装は楽だ。正面から行くと遅延セグ木になるんだよな(やるだけ感がある)。最初からセグ木に行けばこの発想も出るだろうけど。

G - Vertex Deletion

最大マッチングはよくわからないが、頂点iを使わない最大マッチングからその頂点を使って大きくできるかという話。全方位木DP。根を使わずに最大マッチングを実現できる部分木があれば、その頂点は条件を満たさない(根とつなげれば大きくなる)。全ての部分木についてそれがわかればいい。頂点iを根として、子に1頂点の部分木がいくつかと2頂点の部分木がいくつかある場合を考え、実験的にそれっぽい式をでっちあげる。1頂点の部分木は、親がいればマッチングが大きくなる。2頂点の部分木は、親がいても最大マッチングの大きさは変わらない。2頂点のがいくつあっても状況は変わらないのでこれを0で表す。1頂点のが一つでもあると親が役立ってしまう。そういうのを1で表し、ORで結合して根(親)を加えてまとめるときにNOTする。それっぽい。サンプルが通ったので提出してAC。全方位木DPは抽象化しておくとほんとにわずかな変更でACできてしまう。残り30分を切っていたので最初は解けると思っていなかったが、解けるときはあっという間だ。