ABC357

6完。以前と比べてブログ書き終わるの遅いよね。なんで。

A - Sanitize Hands

消毒液の使い方は貪欲(後の人のために残したりはしない)。MからHの要素を順に引いていって、0以上だった回数を数える。

(追記)サニタイズってそういう意味だったのか。

B - Uppercase and Lowercase

islowerやtoupperを使う。簡単だが面倒で時間かかった(面倒な問題だという主張ではない)。

C - Sierpinski carpet

250点でこれは難しすぎるだろ。しばらく考えて愚直に構築できると気づいた。しかも、レベルK+1のカーペットの左上はレベルKのカーペットと同じ、つまり2次元配列1個でできる。あとは問題文の通りにコピーしていくが、memcpy使ったら添え字間違って時間かかった。

(追記)愚直に1マスずつ再帰でできた。言われた通りに実装するだけの問題なんだなあ。

D - 88888888

桁数を調べて等比数列の和。Nを桁数倍したら微妙にオーバーフローする。少し考えたが、powを2回に分けてやればいいと気づいた。割り算は10の冪だから998244353と互いに素で大丈夫とか思ってたけど今見たら1引いてるじゃん!どうやって示すんだと思ったけどよく考えたら10^19-1までだからあるわけないわ(全探索できるし、あったら話題になってる(は?))。こういう、気づかない奴が結果得をする展開嫌い。

(追記)フェルマーの小定理から、(10^998244352-1)%998244353が0になるのだった。気づかなかった。全探索したところ、他に0になる桁数はなかった。また、0になりうるとしても、そのときは行列累乗を使えばいい。

E - Reachability in Functional Graph

こんな典型が残ってたんだね。グラフの形を思い出すのに時間がかかった。各頂点についていくつの頂点に行けるかを求める方針。ループ外の頂点であれば、行き先の頂点の答えがわかればそれに1を足せばいい。あとはループ内の処理だけで、DFSで祖先を発見したら(探索深さを持っておくことで)ループの長さを求めて、その長さぶんは後退しながら1を足さないようにする。長さ1のループはしっかり考える。DFSは単に各頂点からやればよい(初めて探索する連結成分でない場合、ループは既に探索済み)。なかなかサンプルが合わず、サンプル3のグラフを図に描いている途中で気づいた。残り後退回数が0より大きいという条件を逆にして0に等しいとしてしまっていた(負になることもある実装だった)。SCCも考えはしたけどなあ。

(追記)atcoder::scc_graphを使って解き直した。SCCしたら、トポロジカル順で後ろからDPする。閉路はそのサイズを各頂点に入れて、それ以外は1個の出辺があるのでその行き先+1。どの強連結成分からも高々1個の辺しか出ていないことを使っている(コンテスト中はそこまで意識できなかった)。views::reverseで範囲forを逆順に回すの初めてやった。

F - Two Sequence Queries

とりあえず遅延セグ木でできたら嬉しい見た目。できるだろうということで書いていくことで確かめると、けっこう簡単にできる。足すやつはほんとに足すだけだし、モノイドはAの和とBの和とA*Bの和でいい。サンプルが合わず、かなり考えて正しいようにしか見えず、セグ木の中身を出力させて時間かけて足し算とかして最初Bの全体の和が0になってることに気づく。モノイドの演算でAは足し算だがBだけなぜか掛け算になっていた。そこを直してもまだサンプルは合わない。みるみる時間が減っていき、残り2分で作用のところが思いっきり別の問題やってたことに気づく。和の積ではなく積の和だ。なんとなく感覚で、区間の幅を掛けているところを4個中2個外したらサンプルが合って、提出してAC。

(追記)ACLで書き直す(以下、ALCの遅延セグ木に渡すSとFをそのまま書く)。最初、区間の長さをFに持たせようとして混乱していた。解説見たらSに持たせてた。そうだっけ。そうだった。Sの単位元は長さ0なので、全要素に長さ1を入れる必要がある。自前のより遅くなってしまった。ACLは速いけど区間の長さを持たないといけないので。どっちの設計がいいかはわからんなあ。