Loading

4595. 【NOIP2016模拟7.8】String

Description&Data Constraint

有两种字符串 \(S,T\)。长度分别为 \(n,m\)。现在需要在 \(S\) 里面有序地选出 \(k\) 个子串,且在 \(T\) 中出现的顺序与这 \(k\) 个子串的顺序相同。问这k个子串最大的长度和。

\(n,m\le10^3,k\le10\)

Solution

比较经典的 \(dp\)​。

考虑 \(f_{i,j,k}\) 表示 \(S\) 到了第 \(i\) 位,\(T\) 到了第 \(j\) 位,已经选择了 \(k\) 个子串的最大长度和。

但是由于当前位能否匹配与上一位有关,因此再开一维 \(0/1\) 表示 \(i-1\)\(j-1\) 是否匹配。

转移:

如果 \(S_i=T_j\),说明当前位可以匹配,那么 \(f_{i,j,k,1}=\max(f_{i-1,j-1,k,1},f_{i-1,j-1,k-1,0})+1\)

然后 \(f_{i,j,k,0}=\max\{f_{i-1,j-1,k,0/1},f_{i,j-1,k,0/1},f_{i-1,j,k,0/1}\}\)

因为可以有空串,所以 \(ans=\max\{f_{n,m,1\texttt{->}k,0/1}\}\)

Code

#include<cstdio>
#include<algorithm>
#define N 1005
#define K 11
using namespace std;
int n,m,kk,x,ans,f[N][N][K][3];
char ch,a[N],b[N];
int main()
{
	scanf("%d%d%d",&n,&m,&kk);
	ch=getchar();
	while (ch<'a'||ch>'z') ch=getchar();
	x=0;
	while (ch>='a'&&ch<='z') a[++x]=ch,ch=getchar();
	while (ch<'a'||ch>'z') ch=getchar();
	x=0;
	while (ch>='a'&&ch<='z') b[++x]=ch,ch=getchar();
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			for (int k=1;k<=kk;++k)
			{
				if (a[i]==b[j]) f[i][j][k][1]=max(f[i-1][j-1][k-1][0],f[i-1][j-1][k][1])+1;
				f[i][j][k][0]=max(max(max(f[i-1][j-1][k][0],f[i-1][j-1][k][0]),max(f[i][j-1][k][0],f[i][j-1][k][1])),max(f[i-1][j][k][0],f[i-1][j][k][1]));
			}
	for (int i=1;i<=kk;++i)
		ans=max(max(f[n][m][i][1],f[n][m][i][0]),ans);
	printf("%d\n",ans);
	return 0;
} 
posted @ 2021-09-04 14:58  Thunder_S  阅读(35)  评论(0编辑  收藏  举报