CF682D Alyona and Strings

CF682D Alyona and Strings

题意

题目描述

给定两个字符串 \(s\)\(t\),长度分别为 \(n\)\(m\)。要求找出 \(k\)不相交的非空子串 \(p_1,p_2,...,p_k\),满足:

  1. 这些子串在 \(s\)\(t\)按相同顺序出现
  2. 子串在 \(s\)\(t\) 中均不相交(不重叠)
  3. 最大化这些子串的长度之和

数据范围

  • 字符串长度:\(1 \leq n,m \leq 1000\)
  • 子串数量 \(k\)\(1 \leq k \leq 10\)
  • 字符集:小写字母

题解

观察到 \(n,m\) 只有 \(1000\),考虑 \(nm\) dp。

\(dp[i][j][k][0/1]\) 表示字符串 \(s\) 的前 \(i\) 位与字符串 \(t\) 的前 \(j\) 位,一共截断了 \(k\) 次,以及当前位选或不选 (\(0/1\)).

转移显然(见代码)。

注意,这么 dp 可能导致 MLE,可以把 int 改成 short 或者用滚动数组优化(我用了前者,比较懒)。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,p,ans;
char a[2010],b[2010];
short dp[2010][2010][11][2];
int main()
{
	cin>>n>>m>>p>>(a+1)>>(b+1);
	for(int i=0;i<=n;i++)
		for(int j=0;j<=m;j++)
			for(int k=1;k<=p;k++)
                dp[i][j][k][0]=dp[i][j][k][1]=-1e4;
	for(int i=1;i<=n;i++)
	{
        // cout<<i<<endl;
		for(int j=1;j<=m;j++)
		{
            // cout<<"=>"<<j<<endl;
			for(int k=0;k<=p;k++)
			{
				dp[i][j][k][0]=max(dp[i-1][j-1][k][0],max(dp[i-1][j][k][0],dp[i][j-1][k][0]));
				dp[i][j][k][0]=max(dp[i][j][k][0],max(dp[i-1][j-1][k][1],max(dp[i-1][j][k][1],dp[i][j-1][k][1])));
				if(a[i]==b[j] && k) dp[i][j][k][1]=max((int)dp[i][j][k][1],max(dp[i-1][j-1][k-1][0],dp[i-1][j-1][k][1])+1);
                // cout<<dp[i][j][k][0]<<" "<<dp[i][j][k][1]<<endl;
			}
            // cout<<endl;
		}
        // cout<<endl;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			for(int k=0;k<=p;k++)
            {
                if(k==p) ans=max(ans,(int)max(dp[i][j][k][0],dp[i][j][k][1]));
                else
                {
                    if(dp[i][j][k][0]>=p) ans=max(ans,(int)dp[i][j][k][0]);
                    if(dp[i][j][k][1]>=p) ans=max(ans,(int)dp[i][j][k][1]);
                }
            }
	cout<<ans;
	return 0;
}
posted @ 2025-05-10 21:45  crazy--boy  阅读(7)  评论(0)    收藏  举报