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] eq 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{egin{aligned}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] eq B[j-1]end{aligned} ight. ]

[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;
}
原文地址:https://www.cnblogs.com/IzumiSagiri/p/15068164.html