题目描述
字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列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;
}