CF682D Alyona and Strings
CF682D Alyona and Strings
题意
题目描述
给定两个字符串 \(s\) 和 \(t\),长度分别为 \(n\) 和 \(m\)。要求找出 \(k\) 个不相交的非空子串 \(p_1,p_2,...,p_k\),满足:
- 这些子串在 \(s\) 和 \(t\) 中按相同顺序出现
- 子串在 \(s\) 和 \(t\) 中均不相交(不重叠)
- 最大化这些子串的长度之和
数据范围
- 字符串长度:\(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;
}

浙公网安备 33010602011771号