公式

C - binarydigit 解説 by hitonanode


\(\mathrm{dp}[h][w][s]\) を「問題文の条件を満たす \(h\)\(w\) 列の行列 \(A\) であって、全ての要素が共通の行や共通の列が存在せず、かつ \(1\) 行目と \(1\) 列目に \(1\) の要素が存在し、最終列( \(w\) 列目)の値たちが \(s = (A_{1, w}, \dots, A_{h, w})\) であるものの個数(を \(M\) で割った余り)」とおいて、DP を回すことを考えます。

\(\mathrm{dp}[h][w][s]\) から \(\mathrm{dp}[*][w + 1][s_{\mathrm{next}}]\) への遷移は、\(s\)\(s_{\mathrm{next}}\) のタイブレークが起きる位置に注目して場合分けします。タイブレークが起きる桁やそれより下の桁では、\(s\)\(1\) 桁に対して \(s_{\mathrm{next}}\)\(2\) 桁が対応する可能性があります。例えば、

\[ \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix} \]

という \(2\) 列の行列の右に \(1\) 列追加して \(3\) 列の行列に遷移する際、単に \(1\) 列増える

\[ \begin{pmatrix} 0 & 1 & 1 \\ 1 & 0 & 1 \end{pmatrix} \]

という遷移だけでなく、もとの行列の \(2\) 行目を複製した

\[ \begin{pmatrix} 0 & 1 & 1 \\ 1 & 0 & 0 \\ 1 & 0 & 1 \end{pmatrix} \]

という遷移や、これまでの \(1\) 行目より上の行でタイブレークが起きる

\[ \begin{pmatrix} 0 & 0 & 1 \\ 0 & 1 & a \\ 1 & 0 & b \end{pmatrix} \]

のような遷移( \(a\)\(b\) にはそれぞれ「\(0\)」 or 「\(1\)」 or 「行が \(2\) 行に複製され、各行に \(0\)\(1\) が入る」のいずれかが入る)なども考える必要があります。

この DP の実装にあたって、タイブレークが起きる桁より下位の桁の情報を潰していく処理や、タイブレークが起きる桁より下位の桁を 「\(0\)」 / 「\(0\)\(1\)」 / 「\(1\)」 の \(3\) 通りに分岐させる処理を効率的に実装することで、 \(O(2^H W)\) で動作するアルゴリズムが得られます。

投稿日時:
最終更新: