AGC009-C:Division into two
きれいな問題だなあと思った。
解法
簡単のためとする。逆のときはswapしても問題ない。こんなのdpしかないやろという見た目がするので,dpを考える。制約を無視すれば,今何番目の数を見てるかということと,またはに最後に振り分けた数はどれだったかということが必要に見える。そこでを「番目まで振り分け済みで,最後にに振り分けた番号がのときの振り分け方の総数」とできる。遷移は,①ならからに遷移できる。また,として,について,②かつ,からの間の項間の差がすべて以上であるときに,からに遷移できる。(なぜからかというと,でも,をに振り分けているから,はに振り分ければ問題ないからである。)もちろんこれを愚直にやるとで,到底間に合わない。
よく考える。まず,「からの間の項間の差がすべて以上である」かということをdpの更新のときに逐一調べる必要はない。つまり,であれば,より手前の数は,これ以降②タイプの遷移が不可能だとわかるので,そういう番号を管理する変数を持っておけばよい。これをとし,定義を「現時点で②のタイプの遷移が可能な番号の最小値」とする。さらに,をみたす最大のを二分探索し,それをとすると,に遷移してくるのはのつ目の添え字がからまでの数である。だから,累積和を取っておけば②のタイプの遷移はで可能である。
タイプ①の遷移だが,これはつ目の添え字が増えるだけである。タイプ②の遷移も,つの目の添え字は増えるだけだから,結局を「最後にに振り分けた数の番号がであるときの振り分け方の総数」として,これをが小さい順に埋めれば十分である。最後に,明らかに答えがになるパターンの存在に気を付けよう。それは,あるが存在してとなることである。をにもにも振り分けることができなくなるからだ。
以上より,次のようにすればよい。
- となるがあったら答えは。
- を「最後にに振り分けた数の番号がであるときの振り分け方の総数」とし,とする。また,を「現時点で遷移してくることが可能な番号の最小値」とし,とする。が小さい順にこれを埋める。最初に,とする。をみたす最大のをとし,であればとする(のときは遷移できない)。最後に,であればとする。
- 答えは,である。
実装
Submission #4183566 - AtCoder Grand Contest 009
二分探索のとき,のときの扱いに注意。あとのときも注意。
ちゃんと考察すると綺麗な遷移でコードも短い,好き。