Loading

CF1446B

Solution:

根据题目描述我们可以知道一个事情,就是每当字符串 \(a\)\(b\) 只要子串中多一位,那么答案就会少一,如果匹配的子序列多一个字母,那么答案就会多二。以此我们就可以设计出一个 \(dp\) 状态,\(f[i][j]\) 表示以字符串 \(a\) 的第 \(i\) 个位置为结尾和以字符串 \(b\) 的第 \(j\) 个位置为结尾答案最大是多少。可以得到一个转移方程:

\(f[i][j]=max\begin{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\n%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;
}
posted @ 2020-12-21 21:03  ForeverOIer  阅读(75)  评论(0编辑  收藏  举报