LibreOJ 2424 子串
题目链接:LibreOJ 2424 子串
题目大意:
题解:
设\(dp[j][k]\)表示字符串\(A\)判断到第\(i\)个字符且一定取第\(i\)个字符,组成字符串\(B\)的前\(j\)个字符,用了\(k\)个子串的方案数。
设\(DP[j][k]\)表示字符串\(A\)判断到第\(i\)个字符但不一定取第\(i\)个字符,组成字符串\(B\)的前\(j\)个字符,用了\(k\)个子串的方案数。
-
若\(A[i-1]\neq B[j-1]\),则\(dp[j][k] = 0\);
-
若\(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;
}