Codeforces Round #732 (Div. 1)_C AquaMoon and Permutations
あまりに解説が薄すぎてかなり苦労をしたのでメモ
~~問題概要~~
のサイズの行列を考えます。
各行は、 の順列です。
上半分は、ラテン方格になっています。
下半分は、ラテン方格とは限りません。
全ての について を満たす が存在します。
の行をシャッフルした行列が与えられるので、 個の行の選び方のうち、それらを繋ぎ合わせたものがラテン方格となる選び方を数えあげ、更に一つ構築してください。
解説
公式の解説はこちら
解説が短すぎる…というわけで、証明も含めて分かりやすく解説していきたいと思います。
列目に、数 がある状態をタプル で表したいと思います。
すると、各行は 個のタプルの集合と言い換えられます。
この時、問題は、 個の行から 個の行を選んで、 種類ある全てのタプルを揃える問題と言い換えることができます。各行が 個のタプルを持つので、全種類のタプルを個ずつ揃える必要があります。
まず、固有(1回しか登場しない)のタプルを持つ行は必ず採用されます。このような行を全てpickupします。
pickupした行と、共通のタプルを持つ行は選ばれることはありません。このような行をすべて削除します。
削除した後、削除していない行の集合に新たな固有のタプルが生まれた場合、それを含む行もpickupします。これを再帰的に行います。
操作後、pickupも削除もされていない行の集合について考えます。まず、問題のこの部分に着目します。
- 全ての について を満たす が存在する。
すなわち、1つの行がpickupされるとそれに対応する行は、をpickupした時か、それ以前に必ず削除されています。
pickupした行の数以上の数の行が削除行きになっているため、 に含まれる行の内、半数以上が の上半分由来です。
に含まれる行のうち、 個が上半分由来だとしましょう。
まず、 に含まれる行に含まれるタプルは、全て 内に2回以上登場します。これは、固有のタプルを含む行は全てpickupしたことから自明です。
また、上半分由来のタプルは重複しません(上半分はラテン方格なので)。
そのため、上半分由来の行の持つタプルの種類数は 個で、全て つずつです。
上半分由来ではない行の個数を、 とします。これが含むタプルの個数は、個です。全ての種類のタプルは2回ずつ登場しなくてはいけないので、 個の中には上半分由来の 種類のタプルが全て含まれています。 であることから、 が示され、全てのタプルが にちょうど2回だけ登場することが分かります。さらに言えば、全てのタプルが上半分由来の行と、下半分由来の行にちょうど1回ずつ登場します。
さて、各行をノードとしたグラフを考えます。
同一のタプルを持つノード間に辺を引くと、これは二部グラフになります。
この二部グラフのサイズがの頂点集合のうち、全ての辺について両端点の内、ちょうど片方だけが集合に含まれているような頂点集合の個数を求めればよいです。
グラフの形の特殊性から、これは連結成分数 とするとになります(実は二部グラフなら常に成立しますね)。
まず、上半分由来の頂点と下半分由来の頂点はペアになっていると考えられます。上半分由来の頂点には、タプル を持つ下半分由来の頂点をペアにすればいいですね。
つまり、グラフは以下のような形になります。
縦の2頂点が対応していると考えてください。縦のペアのうち、赤か青のどちらかを選ばないと行けませんが、1箇所赤を選ぶと決めると、芋蔓式に連結成分内全て赤を選ばないといけなくなるのがわかると思います。
これで問題を解くことができました。めちゃくちゃ難しいですね……
実装も重くて大変でした まだバグが残ってる可能性も高いです