Official

C - chokudai Editorial by sugarrr


動的計画法(DP)を用います。
\(dp[i][j]\) を、「 \(S\)\(i\) 文字目までを使って、chokudai\(j\) 文字目まで選択する方法」と定義します。
ここで、\(N=|S|\) , \(T= \)chokudai として、以下の漸化式が成り立ちます。

\(\displaystyle dp[i][j] = \begin{cases} 1 & ( j = 0) \\0 & ( i=0 , 1 \leq j \leq 8) \\dp[i-1][j]& ( 1 \leq i \leq N , 1\leq j \leq 8, S[i] \neq T[j] ) \\dp[i-1][j] + dp[i-1][j-1] & (1 \leq i \leq N , 1\leq j \leq 8, S[i] = T[j])\end{cases}\)

なぜ漸化式が成り立つのか分からない

  • \(j=0\) のとき
    chokudai\(0\) 文字目まで選択する」というのは、下線を全く引いていないことを表します。つまり \(1\) 通りです。

  • \( i=0 , 1 \leq j \leq 8\) のとき
    \(S\)\(0\) 文字目までを使う」すなわち「 \(S\) からまだ \(1\) 文字も使っていない」時に、「 chokudai\(j (j \geq 1)\) 文字目まで選択する」ことはできません。つまり \(0\) 通りです。

  • \(1 \leq i \leq N , 1\leq j \leq 8\) のとき

    • \(S[i] \neq T[j]\) のとき
      \(S\)\(i\) 文字目までを使って、\(T\)\(j\) 文字目まで選択する方法」を考えていますが、\(S\)\(i\) 文字目と \(T\)\(j\) 文字目が異なるので、\(S\)\(i\) 文字目に下線を引くことはありえません。よって「 \(S\)\((i-1)\) 文字目までを使って、\(T\)\(j\) 文字目まで選択する方法」の場合の数と等しいです。つまり \(dp[i-1][j]\) 通りです。

    • \(S[i] = T[j]\) のとき

      • \(S\)\(i\) 文字目に下線を引かない時
        先程の議論から、これは \(dp[i-1][j]\) 通りです。

      • \(S\)\(i\) 文字目に下線を引く時
        これは、「 \(S\)\((i-1)\) 文字目までを使って、\(T\)\((j-1)\) 文字目まで選択する方法」の場合の数と等しいです。つまり \(dp[i-1][j-1]\) 通りです。

      まとめると、\(dp[i-1][j] + dp[i-1][j-1]\) 通りです。


for文の \(2\) 重ループを用いて、\(i, j\) が小さい順に \(dp[i][j]\) を全て求めることができます。
最終的な答えは \(dp[N][8]\) です。
このアルゴリズムの計算量は \(O(N)\) で、十分高速です。

posted:
last update: