P2516 [HAOI2010] 最长公共子序列

题目描述

字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X={x0,x1,⋯ ,xm−1},序列Y={y0​,y1​,⋯,yk−1​} 是 X 的子序列,存在 X 的一个严格递增下标序列 {i0​,i1​,⋯,ik−1​} ,使得对所有的 j=0,1,⋯,k−1 ,有 xij​=yj​ 。例如,X="ABCBDAB" ,Y="BCDB"  是 X 的一个子序列。对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。

输入格式

第一行为第一个字符序列,都是大写字母组成,以 . 结束,大写字母个数不超过 50005000。

第二行为第二个字符序列,都是大写字母组成,以 . 结束,大写字母个数不超过 50005000。

输出格式

第一行输出上述两个最长公共子序列的长度。

第二行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对 108108 求余即可。

输入输出样例

输入 #1

ABCBDAB.
BACBBD.

输出 #1

4
7

Solution

#include<bits/stdc++.h>
#define RG register
#define I inline
#define R RG int
#define G c=getchar()
using namespace std;
typedef long long LL;
const int N=5009,YL=1e8;
char x[N],y[N];
int ff[N],gg[N],mff[N],mgg[N];
int main(){
    scanf("%s%s",x+1,y+1);
    R n=strlen(x+1)-1,m=strlen(y+1)-1,i,j,*f=ff,*g=gg,*mf=mff,*mg=mgg;
    g[0]=1;for(j=0;j<=m;++j)f[j]=1;
    for(i=1;i<=n;++i,swap(f,g),swap(mf,mg)){//滚动数组
        memset(g +1,0,m<<2);//注意清空
        memset(mg+1,0,m<<2);
        for(j=1;j<=m;++j){//三方向转移
            if(x[i]==y[j])mg[j]=mf[j-1]+1,g[j]=f[j-1];
            if(mf[j]>mg[j])mg[j]=mf[j],g[j]=f[j];//覆盖
            else if(mf[j]==mg[j])(g[j]+=f[j])%=YL;//相加
            if(mg[j-1]>mg[j])mg[j]=mg[j-1],g[j]=g[j-1];
            else if(mg[j-1]==mg[j])(g[j]+=g[j-1])%=YL;
            if(mf[j-1]==mg[j])(g[j]+=YL-f[j-1])%=YL;//减掉重复的部分
        }
    }
    printf("%d\n%d\n",mf[m],f[m]);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值