ABDEFの5完。Cを12分ほど考えて飛ばして戻ってこなかったが、これが(珍しく)奏功してFがギリギリ間に合った(間に合わなかったとしても、面白いEFに時間を使ったほうがよい)。あと2分遅れていたらこんな穏やかな気分ではいられなかったはずでね。ごめんCを解かずに黄パフォ取るの気持ちいい。
A - Happy New Year 2025
A問題はこのくらいがいいんだよ。
B - 9x9 Sum
B問題はこのくらいがいいんだよ。積を求めて変数に入れておく。
C - Snake Numbers
N以下のヘビ数の個数を求める関数を作ればいい。例えば3で始まる8桁のヘビ数が何個あるかは簡単にわかる。あとは、Nと桁数が同じで最上位桁も同じヘビ数の個数がわかればいいが、これは桁毎にやる必要がありかなり面倒だ。C問題だし何か楽な方法があるのではないかと考えるが、わからない。桁DPで殴れないかと思ってテンプレを貼ってみたが、何をしていいかわからない。ABCの時間を使い切れば最初の方針で通せるだろうが、こんなつまらないことに時間を使ってもしょうがないので飛ばした。
D - Snaky Walk
初手を縦横で2回やるのめんどくさそうだなあと思いながら考えていた。頂点数を2倍にするやつを使えば典型に落とし込めそうなのでそうした。運良くスムーズにACできた。
あとから考えると解説のやり方みたく余計なメモリを使わずにできるなあ。
E - Digit Sum Divisible 2
全然わからんので実験してみる。実験コードを使った愚直でNが小さい(10^6未満)ときは解ける。Nが大きいときは常にできるんだろうなあと当たりをつけて考えていく。「良い整数」はかなり多い。「双子の良い整数」も多く、この一部にいい性質があったとしても見つけるのが難しそう。しばらくにらめっこして、(2000, 2001)のような組があると気づいた。これは桁数が増えても「双子の良い整数」だ。しかし、4000とかだと1を足しても3の倍数にならないし1を引いたら桁和が増えてしまう。範囲が[N, N*2)なのでねえ。これが[N, N*10)だったら楽なんだけど。他のアイデアとしては、桁和をとってもmod 9は変化しない、8で割り切れるかの判定は下3桁でできる、2倍の範囲で桁和を小さくすることはできる(N=2345のとき3000は桁和が小さい)、など。10^9くらいの大きい数でも実験した。桁和が8と9の組をよく見かけたのでそれ固定で探索してみると、やっときれいな法則性が見えた。桁和が8で下3桁が0なら「良い整数」だし、それに1を足せば桁和が9で9の倍数だから「良い整数」だ(希望が見えてからも実験を繰り返しこのことを少しずつ理解していった)。あとは実装だが、桁数が6以下なら愚直。そうでないとき、上3桁を取り出してTとし、T+1からT*2-1までを全探索する。桁和が8になるものが見つかったら元のNの桁数-3個の0にくっつけて出力する(まあ最低でも100個くらいあるからどれかは桁和が8になるでしょ(全探索で証明できるとは思ったがやらなかった))。桁数が増えるケースがずっと怖かったが、この方法なら自然に対処できている。
F - Count Arrays
頑張って具体例を追って問題の意味を追うと、グラフの気分になってくる。自分はこいつ以下だという矢印が出ている。これが「以上」でも「以下」でも答えは変わらないので、特に区別せず(そのときどきでやりやすいように)考えていった。DAGにならない場合を調べるが、よく考えると頂点と辺の数が同じなのでサイクルにひげが付いたやつにしかならない。つまり、サイクルを発見してそこを根とした木でDPなりして問題を解けばいい。ここはかなり悩んだが、atcoder::scc_graphを使った。強連結成分に複数の頂点が含まれる場合は適当に最初の頂点に代表させ新たにグラフ(森)を構築する。構築するとき同じ強連結成分の頂点からの辺は無視しなければならないと気づいてstd::setを使った(時間がないので重い処理も迷いなく入れる)。入次数が0の頂点を根とみなし、DP。ここで、DPが実はそこまで簡単ではないことに気づく。その頂点が例えば3になるのが何通りか求めるとき、子が3の通り数だけでなく2や1や0(0-indexedでやっている)の情報も必要だ。二乗の木DPとも違うしちょっと困ったけど、これは累積和をとれば対応できる。子の累積和を使って「jである通り数」をそれぞれ求めたら、累積和をとって「j以下の通り数」にする。残り時間の少ない中でサンプルが通らず絶望感が出てくるが、落ち着いて内部の数値を(どれを出せばいいかわからんけどとにかく)出力してみてそれを見た自分が何か感じるのを待つ(ちゃんとこのムーブができるのはえらい)。どうも正しそうなので全体を見直すと、各根からDFSするはずが代表となった頂点以外も全部対象になっていたと気づく。代表だけの入次数をチェックするようにしてサンプルが通ったので提出してAC。頂点数1の木をDFSしても1を掛けるだけで問題ないはずなのになんでこれで出力が変わったんだと疑問だったが、あとから考えると、累積和によってMが掛かってくる(そりゃそうだ最初のイメージをひきずっていた)(サイクル内の頂点は全部同じ数でないといけないからね)。あと、最初のころから、グラフの向きを逆にしても行けそうだけどそれはおかしくないかみたいな不安があって、それは、出次数が1だから入次数のほうをチェックするみたいにちゃんと対称性が(あった/崩れていた)(よくわかってないからどっちでもしっくりきて困る)。