zoukankan      html  css  js  c++  java
  • [HAOI2010] 最长公共子序列

    求两个字符序列的最长公共子序列以及个数,(nleq 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] eq 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]<<"
    "<<g[n&1][m]<<endl;
    }
    
    
  • 相关阅读:
    数据类面试题
    java二进制文件复制
    String源码
    集合类题目
    OBJ-C
    java文件(文件夹)操作
    java中输入方式Scanner和BufferedReader
    二次分发举例
    Eclipse常用快捷键
    c#获取新浪微博登录cookie
  • 原文地址:https://www.cnblogs.com/mollnn/p/12390071.html
Copyright © 2011-2022 走看看