LibreOJ 2424 子串

题目链接:LibreOJ 2424 子串

题目大意:

题解:
\(dp[j][k]\)表示字符串\(A\)判断到第\(i\)个字符且一定取第\(i\)个字符,组成字符串\(B\)的前\(j\)个字符,用了\(k\)个子串的方案数。
\(DP[j][k]\)表示字符串\(A\)判断到第\(i\)个字符但不一定取第\(i\)个字符,组成字符串\(B\)的前\(j\)个字符,用了\(k\)个子串的方案数。

  1. \(A[i-1]\neq B[j-1]\),则\(dp[j][k] = 0\)

  2. \(A[i-1]=B[j-1]\),可以选择将\(A[i-1]\)加在\(A[i-2]\)后面算作一个子串,则此时\(A[i-2]\)必须可取且要一定取,方案数为\(dp[j-1][k]\);若将\(A[i-1]\)算作一个新的子串,则\(A[i-2]\)不一定取,方案数为\(DP[j-1][k-1]\),则状态转移方程为:

\[\left\{ \begin{array}{l} dp[j][k] = dp[j - 1][k] + DP[j - 1][k - 1], A[i - 1] = B[j - 1] \\ dp[j][k] = 0, A[i - 1] \neq B[j - 1] \end{array} \right. \]

\[DP[j][k] = \sum_{1}^{i} dp[j][k] \]

看到这肯定发现\(i\)所在的那一维被压缩了,所以在\(j\)的循环里,\(j\)是从\(m\)\(1\)递减更新答案的(可以联想\(01\)背包压缩成一维数组)。

#include <iostream>
#include <string>
using namespace std;
#define N 1010
const int mod = 1e9 + 7;

int dp[210][210], DP[210][210], n, m, t;
string a, b;

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m >> t;
    cin >> a >> b;
    dp[0][0] = DP[0][0] = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = m; j >= 1; --j) {
            for (int k = 1; k <= t; ++k) {
                if (a[i - 1] == b[j - 1]) {
                    dp[j][k] = (dp[j - 1][k] + DP[j - 1][k - 1]) % mod;
                    DP[j][k] = (DP[j][k] + dp[j][k]) % mod;
                } else {
                    dp[j][k] = 0;
                }
            }
        }
    }
    cout << DP[m][t];
    return 0;
}
posted @ 2021-07-27 22:07  ZZHHOOUU  阅读(26)  评论(0编辑  收藏  举报