AGC017-F ZigZag
https://atcoder.jp/contests/agc017/tasks/agc017_f
で解きます。
左に曲がったら 0, 右に曲がったら 1 として折れ線を 2 進数に変換します。 隣りあった折れ線に対応する整数について、01 の列の累積和を取ったものが、どの index についても右の方が大きいことが必要十分です。
今、右側の折れ線を固定し、一個左の折れ線としてあり得るものはどんなものなのかを観察します。 右の折れ線に対応する 2 進数に 1 が登場する回数を 回とします。左側で登場できる 1 の個数は明らかに 回以下です。 左側で登場する 1 の個数を 回とするとき、右側の 1 は前から 個のみを考慮すればいいことがわかります。
実は、左側で 個目の 1 が登場する index を , 右側を同様に と書くと、任意の について、 が必要十分、と書けます。
今、個数が固定されているので遷移の際 1 番右の 1, 次の 1, とより後ろの 1 から順に高速ゼータ変換っぽく遷移させることでこれらは一気に遷移させることができます。
遷移するためには "10" の順番で並んでいる必要があるので、このような遷移の起きる場所は合計で 箇所です。
結論として、
- 一番右の 1 を消す方向に遷移させる
- より右の 1 から、1 個ずつ右に動かしていく
の順で遷移させることで、すべての遷移をカバーできます。 提出コード