Alyona and Strings CodeForces - 682D DP
题目大意:
给你两个长度均小于等于1000的字符串,你要在第一个串中找k(k<=10)个连续的子串,并且这些字串在第二个字符串中均出现且顺序相同,问这些字串最大的长度和。
题目分析:很显然,如果没有k个子串的限制的话,就是一个最大公共子序列的问题。现在就是K个最大公共子序列的问题了。
当时想的时候,是用的三维数组,多开了一维来表示k个,然后就发现当我判断要不要多加一个来隔开他们的时候,需要判断他们是不是连续的,然后就想不出来了。
dp[i][j][k][0]表示第一个字符取前i个,第二个字符取前j个,已经分配到了k段,这第k段还会继续延伸的最大长度和。
dp[i][j][k][1]表示第一个字符取前i个,第二个字符取前j个,已经分配到了k段,这第k段不会继续延伸的最大长度和。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 100;
int dp[maxn][maxn][20][2];
char str1[maxn], str2[maxn];
int main()
{
int n, m, K;
scanf("%d %d %d", &n, &m, &K);
scanf("%s %s", str1 + 1, str2 + 1);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(str1[i] == str2[j]) {
for(int k = 1; k <= K; k++) {
dp[i][j][k][0] = max(dp[i - 1][j - 1][k][0], dp[i - 1][j - 1][k - 1][1]) + 1;
//dp[i - 1][j - 1][k][0]表示新来的i,j跟之前的在一起
//dp[i - 1][j - 1][k - 1][1]表示新来的i,j独立
}
}
for(int k = 1; k <= K; k++) {
dp[i][j][k][1] = max(max(dp[i - 1][j][k][1], dp[i][j - 1][k][1]), dp[i][j][k][0]);
//dp[i][j][k][1] = dp[i][j][k][0] 是因为可以把想要继续延续下去的ij断开
}
}
}
printf("%d\n", dp[n][m][K][1]);
}