Solution:
根据题目描述我们可以知道一个事情,就是每当字符串 (a) 或 (b) 只要子串中多一位,那么答案就会少一,如果匹配的子序列多一个字母,那么答案就会多二。以此我们就可以设计出一个 (dp) 状态,(f[i][j]) 表示以字符串 (a) 的第 (i) 个位置为结尾和以字符串 (b) 的第 (j) 个位置为结尾答案最大是多少。可以得到一个转移方程:
(f[i][j]=maxegin{cases}0\f[i-1][j]-1\f[i][j-1]-1\f[i-1][j-1]+2;,;a[i]=b[j]end{cases})
(0) 就表示两个子串中最长公共子序列长度为 (0) (f[i-1][j]-1) 表示从字符串 (a) 中增加一位到 (f[i][j]) ,(f[i][j-1]-1) 与上面同理,(f[i-1][j-1]+2;,;a[i]=b[j]) 表示当字符串 (a) 和 (b) 的第 (i) 和 第 (j) 位相同时,对答案贡献为 (2) .
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0' || c>'9'){if(c=='-') f=0;c=getchar();}
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return f?x:-x;
}
const int N=5010;
int n,m,f[N][N],ans;
char a[N],b[N];
int main()
{
n=read(),m=read();
scanf("%s
%s",a+1,b+1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
f[i][j]=max({0,f[i-1][j]-1,f[i][j-1]-1});
if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+2);
ans=max(ans,f[i][j]);
}
}
printf("%d",ans);
return 0;
}