题目传送门
解题思路:
第一问要求最长公共子序列,直接套模板就好了.
第二问要求数量,ans[i][j]表示第一个字符串前i个字符,第二个字符串前j个字符的最长公共子序列的数量
如果f[i][j]是由f[i-1][j]转移过来的,那么ans[i][j] += ans[i-1][j].
如果是从f[i][j-1]或f[i-1][j-1]转移过来的,同上(数组下标变化).
如果f[i][j] == f[i-1][j-1],那么说明f[i-1][j]和f[i][j-1]是从f[i-1][ij-1]转移过来的,那么ans[i][j]就把ans[i-1][j-1]加了两遍,要减去一遍.
还有就是题目中两个字符串的长度都不超过5000,如果直接暴力,会MLE.
那么,这个时候,我们的滚动数组就派上用场了.
最后说明一点,ans的初始值怎么附: 我是设第一次的i为0,那么ans[0][0] = 1,因为长度为1的A和长度为0的B的最长公共子序列有1个.
ans[1][所有] = 1;因为长度为0的A和任意长度的B最长公共子序列的个数都是1.
AC代码:
#include<iostream>
#include<cstdio> using namespace std; const int mod = ;
string l,l1;
int f[][],ans[][],m; inline int max(int a,int b) {
if(a >= b) return a;
return b;
} int main() {
cin >> l >> l1;
for(int i = ;i <= l1.length() - ; i++)
ans[][i] = ;
ans[][] = ;
for(int i = ;i <= l.length() - ; i++) {
for(int j = ;j <= l1.length() - ; j++) {
f[m][j] = max(f[m][j-],max(f[m^][j],f[m^][j-] + (l[i-] == l1[j-])));
ans[m][j] = ;
if(f[m][j] == f[m^][j]) ans[m][j] += ans[m^][j];
if(f[m][j] == f[m][j-]) ans[m][j] += ans[m][j-];
if(f[m][j] == f[m^][j-] + && l[i-] == l1[j-]) ans[m][j] += ans[m^][j-];
if(f[m][j] == f[m^][j-]) ans[m][j] -= ans[m^][j-];
ans[m][j] = ans[m][j] % mod;
}
m = m ^ ;
}
printf("%d\n%d",f[m^][l1.length()-],ans[m^][l1.length()-]);
return ;
}