C - 敵対的引用 Editorial by miscalculation53


一見複雑な構文解析を必要としそうに見えますが、よく考えるとかなり単純な構造をしています。発言の内容 \(s\) を整理すると、問題は次のように述べられます。

\(N\) 頂点 \(M\) 辺の有向グラフがある(\(a\) から \(b\) への辺があるところが「\(a\)\(b\) に攻撃的」に対応するとする)。

頂点番号 \(g_0\) と、\(01\)\(w = (w_1, \ldots, w_K)\) が与えられる。頂点の列 \((g_1, \ldots, g_K)\) があり、次の条件を満たしているという。

  • \(w_i = 1\) のとき、\(g_{i-1} \leftarrow g_i\) の辺が存在する。

  • \(w_i = 0\) のとき、\(g_{i-1} \leftarrow g_i\) の辺は存在しない。

\(g_K\) としてありうるものの個数を求めよ。

$s$ から $g_0$ と $w$ を得る方法 数が現れる前の部分は無視してしまってよいです。数が現れたら、それが $g_0$ です。その後は、
  • $w_1 = 1$ なら w が追加され、$w_1 = 0$ なら何も追加されない
  • $i = 2, 3, \ldots, K$ の順に、$w_i = 1$ なら "ww が、$w_i = 0$ なら " が追加される
という構造になっています。

以下では、頂点 \(j\) から辺が出ている頂点の集合を \(S_j\) とします。

次のナイーブな DP を考えます。

  • \(\mathrm{dp}(i, j) := \, g_i = j\) となる可能性があるか

\[ \mathrm{dp}(i, j) = \begin{cases} \displaystyle \bigvee_{j' \in S_j} \mathrm{dp}(i-1, j') & (w_i = 1) \\ \displaystyle \bigvee_{j' \notin S_j} \mathrm{dp}(i-1, j') & (w_i = 0) \\ \end{cases} \]

記法について $\displaystyle \bigvee_{j' \in S_j} \mathrm{dp}(i-1, j')$ は 「$S_j$ に含まれる $j'$ すべてについて $\mathrm{dp}(i-1, j')$ の or をとったもの」つまり「$S_j$ に含まれる $j'$ のうち $\mathrm{dp}(i-1, j')$ が $1$ のものがあれば $1$、なければ $0$」ということです。

全体計算量は \(O(N^2 K)\) となり、部分点が得られます。

上の解法で時間がかかっているのは、\(j' \notin S_j\) についての遷移をしている部分です。\(j' \in S_j\) に関する遷移(辺が存在するところの遷移)だけで済ませられれば、計算量を \(O((N+M)K)\) に改善することができます。そのためには、or 演算は扱いづらいです。DP に \(01\) の情報だけでなく個数を持たせることにして、遷移を足し算にすることを考えましょう:

  • \(\mathrm{dp2}(i, j) := \, g_i = j\) であるとしたとき、\(g_{i-1}\) としてありうるものの個数(補足:個数が \(1\) 以上なら \(g_i = j\) の可能性があるといえます)

\[ \mathrm{dp2}(i, j) = \begin{cases} \displaystyle \sum_{j' \in S_j} \mathbf{1}[\mathrm{dp2}(i-1, j') > 0] & (w_i = 1) \\ \displaystyle \sum_{j' \notin S_j} \mathbf{1}[\mathrm{dp2}(i-1, j') > 0] & (w_i = 0) \\ \end{cases} \]

記法について 条件 $\mathrm{cond}$ に対し $\mathbf{1}[\mathrm{cond}]$ で $\mathrm{cond}$ が真なら $1$、偽なら $0$ を返す関数を表します。

\(w_i = 0\) の場合の遷移について、\(\displaystyle \sum_{j' \notin S_j} \mathbf{1}[\mathrm{dp2}(i-1, j') > 0] = \sum_{j' = 1}^N \mathbf{1}[\mathrm{dp2}(i-1, j') > 0] - \sum_{j' \in S_j} \mathbf{1}[\mathrm{dp2}(i-1, j') > 0]\) です。第 \(1\) 項は \(j\) によらないので前計算でき、第 \(2\) 項は \(j' \in S_j\) に関する遷移になったので、計算量は \(O((N+M)K)\) となり、満点が得られます。

発想としては、補グラフ上で DP する ABC212 E - Safety Journey に似ています。

posted:
last update: