ABC202

Eまで解いて順位表見てギョッとした。たしかにEで悩んでいるときFを読んでこれはやべえと思ってすぐEに戻ったけど。

Cまでの早解きが今回もできているので、これを保ったまま、水diffくらいの問題も空回りせず力を出せるようにしていきたい(理想を言えば)。

解説にRustの実装例があるのいいね。

A - Three Dice

「和が7」が3組あるので21から引く。

B - 180°

やばげ。最初は「それじゃ文字まで逆さにすると思われちゃうじゃん」と思ったけど、よく読むとまさかの本当に文字まで逆さにするやつ。操作方法が書いてあるので、結局はその通りに実装するだけの問題。無駄に感情の起伏があった。

C - Made Up

かなり難しい。落ち着いて、ひねりがないバージョンから考える。A_i=B_j を数えるなら、個数をカウントして掛ければいい。よって、やはりカウントして掛けるだけでいい。Aは普通にカウント。Bは数列を保存しておいて、Cを読みながらBを参照して現れたBの値をカウント。

D - aab aba baa

典型だけどけっこうな時間糸口が見えなかった(なんか先頭にaがx個並ぶときの通り数とか考えてた)。先頭から決めるだけやんけ。先頭にaが来る通り数はコンビネーションで簡単に求まる(ギリオーバーフローしないようだ)(こういうときパスカルの三角形使えば安全なのまた忘れてた)。入力を受け取った段階でKをデクリメントしておいて、その通り数以上ならbにして引く。すると1文字少ない(aやbが0個の場合もある)問題に帰着される。

E - Count Descendants

Uを根とする部分木のサイズも、深さDの頂点数も簡単。その共通部分をQ個処理する必要がある。しばらく考えて深さ毎の頂点数を管理しながらDFSを思いついたが、結局脳内では解けなかった。いくら考えてもぼやぼやしてるので、解けている確信がないまま実装。まあスピードを求めるなら初手実装しかなかったかなあ。それが最善のムーブとは限らないが。

実装はかなりややこしい。まずクエリを先読みしてU毎に振り分ける(クエリの番号も持つ)。深さ毎の頂点数のvectorと答えを格納するvectorを用意する。DFSして、各Uに対するクエリを処理していく。最初にこの実装が完了したとき、根からUまでのパス上の個数が得られるコードになっていて当然サンプルが通らなかった。間違いに気づき絶望感もあったが、このコードが生かせる問題に違いないとも思い考えているとすぐに修正してACできた。DFSで訪れた頂点をカウントしていくだけでよくて、部分木のサイズは行きと帰りの差でわかる。

各深さの頂点数を格納するvectorのサイズがO(N)、DFSで訪れる頂点数もO(N)、なのに全体でもO(N)で済むというやつ。このタイプの問題、何回解いても面白い。

F - Integer Convex Hull

いやNが80は多すぎでしょ。まとめて考えられるのどこよ。凸80角形の形に点が並んでいる場合を考えると、その中からいくつか選んで辺上の格子点が偶数個になる通り数みたいな。区間DPみたいにしてこれはできる?すると凸包をまず求めて、そこで使った点のうち反時計回りに2個を選んでその2個を使用して偶数になる奇数になるそれぞれの通り数でDPか。面積0がイヤだな。どっちみち何を2個足しても偶数だからいいのかな。途中で新たに関わってくる頂点がヤベエな(三角形の中に三角形が入ってるのを10回繰り返すとかあるし)。そもそも解けないんだけど、それ以上に実装したくない気持ちが。