首页 > 其他 > 详细

[HAOI2010] 最长公共子序列 - dp

时间:2020-03-01 16:00:44      阅读:46      评论:0      收藏:0      [点我收藏+]

求两个字符序列的最长公共子序列以及个数,\(n\leq 5000\)

Solution

第一问,考虑 \(f[i][j]\) 表示两个串分别跑到了 \(i,j\) 位置的最长公共子序列,则
\[ f[i][j]=\max(f[i-1][j],f[i][j-1],f[i-1][j-1]+[s[i]==t[j]]) \]
暴力转移即可

第二问,考虑 \(g[i][j]\) 表示两个串分别跑到了 \(i,j\) 位置的最长公共子序列的方案数,则先正常统计从 \(f[i-1][j],f[i][j-1]\) 过来的方案数,然后考虑两种特殊情况

  • 如果 \(f[i][j]=f[i-1][j-1]\) 并且 \(s[i]\neq t[j]\),那么需要额外减去 \(g[i-1][j-1]\)
  • 如果 \(f[i][j]=f[i-1][j-1]+1\) 并且 \(s[i]=t[j]\),那么需要额外加上 \(g[i-1][j-1]\)
#include <bits/stdc++.h>
using namespace std;
const int mod = 100000000;
int n,m,f[2][5005],g[2][5005];
char s[5005],t[5005];

signed main() {
    cin>>s+1>>t+1;
    n=strlen(s+1);
    m=strlen(t+1);
    --n; --m;
    for(int i=0;i<=n;i++) g[0][i]=1;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) g[i&1][j]=0;
        g[i&1][0]=1;
        for(int j=1;j<=m;j++) {
            f[i&1][j]=max(max(f[i-1&1][j],f[i&1][j-1]),
                        f[i-1&1][j-1]+(s[i]==t[j]));
            if(f[i&1][j]==f[i-1&1][j]) (g[i&1][j]+=g[i-1&1][j])%=mod;
            if(f[i&1][j]==f[i&1][j-1]) (g[i&1][j]+=g[i&1][j-1])%=mod;
            if(f[i&1][j]==f[i-1&1][j-1]&&s[i]!=t[j])
                (g[i&1][j]+=mod-g[i-1&1][j-1])%=mod;
            if(f[i&1][j]==f[i-1&1][j-1]+1&&s[i]==t[j])
                (g[i&1][j]+=g[i-1&1][j-1])%=mod;
        }
    }
    cout<<f[n&1][m]<<"\n"<<g[n&1][m]<<endl;
}

[HAOI2010] 最长公共子序列 - dp

原文:https://www.cnblogs.com/mollnn/p/12390071.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!