Codeforces Round #531 (Div. 3)E. Monotonic Renumeration
問題概要
長さ の数列 に対し, 長さ の数列が以下の条件を満たすとき は Monotonic Renumeration であるという :
- である に対して ならば が成り立つ(逆, つまり ならば は成り立たなくてもよい).
- 任意の に対して もしくは が成り立つ.
与えられた に対して, Monotonic Renumeration な は何通り存在しますか? で割った余りを答えてください.
制約
解説
三つ目の条件から, 数列は広義単調増加でなければならないことがわかります. また更に のとき でければなりませんから, これをみたしながら単調増加を保つには のとき でなければなりません. この条件を満たさなければならない区間は一つにまとめてしまえば, 独立な区間の数を として が答えとなります(次の区間に割り当てる数字は同じ値か 増やした値のいずれかから選べるためです).
そこで独立な区間の数を上手に数えることにしましょう. ここでは, Union-Find を用いた方法を考えます. まずは大きさ の UF を用意します.
から順にみていくことにして, をみたすような を見つけたら, をすべてマージすることにしましょう. これを実装すれば集合の個数が独立な区間の個数になってくれますが, このままだと O(n^2) かかって TLE します. どうすればいいでしょうか?
これは, をすべてマージする過程で, 途中にすでにマージされた区間があった場合に飛ばすような処理を追加すればよいです. 具体的には次のように実装します:
- として初期化する.
- と の が異なるなら と をマージして , 同じなら へと移動
- が になったらループを抜ける.
このように実装すると, 各頂点を見る回数が高々 回に抑えることができます. ただしこれを行うには が常に集合の中での最小の頂点番号にする必要があるので, UF の計算量は になります(が, 十分高速です). ACLを使っているなら, 若干実装をいじる必要があります.
実装
ACL の dsu に新しい関数を追加して上記の実装をしています.