zoukankan      html  css  js  c++  java
  • Jzoj5237 最长公共子序列

    给你序列A和B,求出他们LCS的方案数,|A|,|B|<=5000

    dp套dp经典题目,我们考虑先求出LCS,令f[i][j]表示处理到序列A的第i位,B序列的第j位时的LCS长度

    那么转移很显然,现在考虑如何统计答案

    我们设g[i][j]为当处理到序列A的第i位,B序列的第j位时LCS的方案数

    显然我们要考虑f[i][j]的转移情况

    若f[i][j]=f[i-1][j-1]+1 那么g[i][j]=g[i-1][j-1]

    否则我们看f[i][j]是否和f[i-1][j]和f[i][j-1]相等,如果是就分别对应加上g[i-1][j]和g[i][j-1]

    注意,若有f[i][j]=f[i-1][j]=f[i][j-1]那么g[i][j]要减去g[i-1][j-1](可以类比于二维前缀和)

    答案就是g[n][m]

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define M 1000000007
    using namespace std;
    inline void ad(int& x,long long y){ x=(x+y+M)%M; }
    int f[5010][5010],g[5010][5010],n,m;
    char a[5010],b[5010];
    int main(){
    	freopen("lcs.in","r",stdin);
    	freopen("lcs.out","w",stdout);
    	scanf("%s%s",a+1,b+1);
    	n=strlen(a+1); m=strlen(b+1);
    	for(int i=0;i<=n;++i) g[i][0]=1;
    	for(int j=0;j<=m;++j) g[0][j]=1;
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
    			else f[i][j]=max(f[i-1][j],f[i][j-1]);
    			if(f[i][j]==f[i][j-1]) ad(g[i][j],g[i][j-1]);
    			if(f[i][j]==f[i-1][j]) ad(g[i][j],g[i-1][j]);
    			if(a[i]==b[j]) ad(g[i][j],g[i-1][j-1]);
    			if(f[i-1][j-1]==f[i][j-1]&&f[i-1][j-1]==f[i-1][j]&&f[i][j]==f[i-1][j])
    				ad(g[i][j],-g[i-1][j-1]);
    		}
    	}
    	printf("%d
    %d",f[n][m],g[n][m]);
    }

  • 相关阅读:
    Mac php使用gd库出错 Call to undefined function imagettftext()
    centos 使用 locate
    Mac HomeBrew 安装 mysql
    zsh 命令提示符 PROMPT
    新的开始
    Java 面试题分析
    Java NIO Show All Files
    正确使用 Volatile 变量
    面试题整理 2017
    有10阶梯, 每次走1,2 or 3 阶,有多少种方式???
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/7887162.html
Copyright © 2011-2022 走看看