BAPC2018 E - Entirely Unsorted Sequences
問題
個の数字が与えられるので、その数字を使って作れる数列のうち、以下のような条件を満たす数列の個数をで割った値を求めてください。
- 全ての数字について、その数字より左側に自分より大きいものが存在する、もしくは右側に小さいものが存在する
例えば、{1,4,3}という数列について考えた時、4の右側に3が存在しているので、4は条件を満たしていますが、1より小さい数字は1の右側に存在していないので、この数列は上の条件を満たしていません。逆に、{3,4,1}という数列は上の条件を満たしています。
解法
先輩+解説の解法になります。自分はそれを実装しただけです。
まず、の重複がない場合を考えます。上の条件を満たすものを考えるのは見通しが悪いので、満たさないものを考え、全体から引けばよいです。
上の条件が満たさないものとは、
- 数列のうち少なくとも1つ、左側には全て自身以下の数字が、右側には全て自身以上の数字が並んでいる数字がある
ということです(最初の条件と区別するため、条件Xと呼ぶことにします)。
これを包除原理を用いて求めます。
例えば、の二つが条件Xを満たすとします。
このとき、の3種類の数字の集合が存在しますが、それぞれの中でどのような順番に並び替えても、は条件Xを満たします。
これを踏まえて、以下のようなDPを考えます。
番目までの数列について、番目の要素が条件Xを満たしかつ、全体で個以上の要素が条件Xを満たすようなものの個数
このDPの遷移は、を満たすが条件Xを満たす際、から番目の間の数字はどのような順番にしても、番目の数字はどちらも条件Xを満たすことに注目すると、
となります。
あとは、包除原理を利用して、
が奇数ならば、を足す。
が偶数ならば、を引く。
という操作を繰り返すと、求めたい”少なくとも1つの数字が条件Xを満たす”数列の個数を、重複なく求めることができます。
そして、上のDPはですが、は偶数であるか奇数であるか、という情報さえあればよいので、2通りに絞ることができ、に計算量を落とすことができます。
となります( は0か1です)。
そして、求めた”少なくとも1つの数字が条件Xを満たす”数列の個数を、から引けば、最終的な答えとなります。
さて、順列の部分では、あえて階乗の記号を使わずに記述しました。というのも、数字が重複している場合を考えなければならないからです。
先に全ての数字をソートしておきます。
番目から番目の数字を使った順列の個数
とします。
すると、
となります。
これを前計算しておくことで、上のDPの際に、で計算ができます。
あとは、上のDPとこの前計算を実装すると、この問題を解くことができます。
感想
数えづらいものは全体から逆を引いて求める、高校数学でも時々見かけましたが、肝心なときに思いつきませんね…
今回はさらに、包除原理と重複ありのセットだったので、さらにごたごたしていました。
実装も、他の実装難問題に比べるとマシなはずなのですが、結構やらかした箇所が多かったので、全体的に悔しい結果となりました。