Educational Codeforces Round 99(Div.2) D. Sequence and Swaps 解説
初投稿なので丁寧目に書きました。たぶん今後は徐々にテキトーになります(苦笑)
問題リンク
問題概要
個の非負整数からなる数列と、非負整数が与えられます。次の操作を好きな回数行えます。
操作: より大きいの要素を選択し、とを入れ替える。
数列を広義単調増加にするために必要な操作回数の最小値を求めてください。ただし、不可能な場合はと出力してください。
制約
, ,
ただし、の和は500を超えない。はクエリの個数。
解法
と交換するの要素は必ずより大きいので、スワップを繰り返すにつれては(狭義)単調増加することと、ソート後の数列は左に行くほど小さくなることを考えると、直観的にとスワップできる要素の内、最も左の要素をスワップをしていきたくなります。証明します。
証明
とがスワップできるとします。この時が成り立ちます。ここでとスワップした場合、数列の並びはとなり、です。でしたから、この2要素の並びはこのままではいけません。しかし、さらにをとスワップしてもなので大小関係が逆のままとなります。1回目あるいは2回目のスワップの直後に他から要素を貰ってくることもできますが、は単調増加であり、よりも小さなを貰うことはできないため、番目の位置には以下の要素を置くことができません。よって、2つ以上スワップできる要素があった時、そのうち最も左の要素とスワップするべきであり、逆にその他の要素とスワップするとソートが完遂しません。従ってこれが唯一の手順となり、他の手順が存在しないため、当然最小の手順にもなります。
ただし、途中でスワップできたとしても、ソートが完了していればスワップする意味はありませんので、その時点で終了すべきです。(←自戒)
実装
- 数列がソート済みであるかを確認する。ソート済みなら終了。
- 数列を前から見ていき、スワップできるならばスワップする。
- 最後に数列を確認し、ソートされていれば回数を、ソートされていなければ-1を出力する。
感想
コンテスト中はソート済みかの確認を忘れて1ペナを出してしまいました。今回のコンテストは(少なくともDまでは)、解法がわかってしまえば実装は楽な問題が多かった気がします。あと、解説記事を書くとコンテスト中は適当になりがちな証明を詰めれていいですね。続けていきたいです。