您的位置:首页 > 其它

[bzoj2423][HAOI2010]最长公共子序列

2017-03-27 10:41 218 查看
来自FallDream的博客,未经允许,请勿转载,谢谢。

--------------------------------------------------------------------------------------------------------

给定两个长度为n,m字符串,求最长公共子序列长度和方案数$\mod 10^{8}$ $n,m\leqslant 5000$

题解:第一问相信大家都会...f[i][j]表示第一个字串前i个,第二个字串前j个最长的长度$f[i][j]=\begin{equation}
\left\{
\begin{aligned}
\max(f[i][j-1],f[i-1][j]) \\
f[i-1][j-1]+1(a[i]=b[j]) \\
\end{aligned}
\right.
\end{equation}$

然后第二个问,我们考虑f[i][j]=k,那么就从加上f[i-1][j]和f[i][j-1]中=k的方案数。

如果a[i]=b[j],那么还要算上f[i-1][j-1]的方案数;但是如果a[i]!=b[j]且f[i-1][j-1]=k,就要减去它的方案数了。

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 100000000
#define ll long long
using namespace std;
inline int read()
{
int x = 0 , f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
return x * f;
}

int f[2][5005],r[2][5005];
char s1[5005],s2[5005];
int n,m;

int main()
{
scanf("%s",s1+1);n=strlen(s1+1)-1;
scanf("%s",s2+1);m=strlen(s2+1)-1;
int now=1,pre=0;
for(int k=0;k<=m;k++)r[0][k]=1;r[1][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
f[now][j]=max(f[pre][j],f[now][j-1]);r[now][j]=0;
if(s1[i]==s2[j])f[now][j]=max(f[now][j],f[pre][j-1]+1);
if(s1[i]==s2[j]&&f[now][j]==f[pre][j-1]+1) r[now][j]+=r[pre][j-1];
if(f[pre][j]==f[now][j]) r[now][j]+=r[pre][j];
if(f[now][j-1]==f[now][j]) r[now][j]+=r[now][j-1];
if(f[pre][j-1]==f[now][j]) r[now][j]-=r[pre][j-1];
r[now][j]=(r[now][j]+mod)%mod;
}
now=pre;pre=1-pre;
}
printf("%d\n%d",f[pre][m],r[pre][m]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: