题目:
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5005,mod=100000000;
int d1[2][N],d2[2][N];//滚动数组,最长公共子序列长度,最长公共子序列个数
char s1[N],s2[N];
int main()
{
scanf("%s",s1+1);scanf("%s",s2+1);
int n=strlen(s1+1)-1,m=strlen(s2+1)-1;
int now=1,pre=0;//分别表示当前状态和上一个状态
for(int i=0;i<=m;i++){
//确定边界
//当一条串不选取字符时,最长公共子串数是1
d2[0][i]=1;
d2[1][0]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
//pre为下标的数组就相当于i-1状态
//d1[pre][j]相当于d1[i-1][j],d1[now][j-1]相当于d1[i][j-1]
d1[now][j]=max(d1[pre][j],d1[now][j-1]);
d2[now][j]=0;
if(s1[i]==s2[j]) d1[now][j]=max(d1[now][j],d1[pre][j-1]+1);
/*以下四种情况进行讨论
1、s1[i]=s2[j]且d1[i][j]=d1[i-1][j-1]+1
2、d1[i-1][j]=d1[i][j]
3、d1[i][j-1]=d1[i][j]
4、d1[i-1][j-1]=d1[i][j]
*/
if(s1[i]==s2[j]&&d1[now][j]==d1[pre][j-1]+1) d2[now][j]+=d2[pre][j-1];//最长公共子序列变长了
if(d1[now][j]==d1[pre][j]) d2[now][j]+=d2[pre][j];//从i-1到i,最长公共子序列的长度没有变化
if(d1[now][j-1]==d1[now][j]) d2[now][j]+=d2[now][j-1];//从j-1到j,最长公共子序列的长度没有变化
if(d1[pre][j-1]==d1[now][j]) d2[now][j]-=d2[pre][j-1];//容斥原理,减掉重复的情况
d2[now][j]%=mod;
}
now=pre,pre^=1;//滚动数组,now和pre在0和1之间交换
}
cout<<d1[pre][m]<<endl<<d2[pre][m];
}
总结:
这题的第一问是标准的LCS模板题
第二问的关键在于对于四种情况的分析,既不能多算也不能少算
另外滚动数组也很重要,不然百分百超内存
总体做下来,第一问很快就解决了,第二问一开始没有思路,后面参考了大佬的题解才知道了解题方法