求两个字符序列的最长公共子序列以及个数,(nleq 5000)
Solution
第一问,考虑 (f[i][j]) 表示两个串分别跑到了 (i,j) 位置的最长公共子序列,则
[f[i][j]=max(f[i-1][j],f[i][j-1],f[i-1][j-1]+[s[i]==t[j]])
]
暴力转移即可
第二问,考虑 (g[i][j]) 表示两个串分别跑到了 (i,j) 位置的最长公共子序列的方案数,则先正常统计从 (f[i-1][j],f[i][j-1]) 过来的方案数,然后考虑两种特殊情况
- 如果 (f[i][j]=f[i-1][j-1]) 并且 (s[i] eq t[j]),那么需要额外减去 (g[i-1][j-1])
- 如果 (f[i][j]=f[i-1][j-1]+1) 并且 (s[i]=t[j]),那么需要额外加上 (g[i-1][j-1])
#include <bits/stdc++.h>
using namespace std;
const int mod = 100000000;
int n,m,f[2][5005],g[2][5005];
char s[5005],t[5005];
signed main() {
cin>>s+1>>t+1;
n=strlen(s+1);
m=strlen(t+1);
--n; --m;
for(int i=0;i<=n;i++) g[0][i]=1;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) g[i&1][j]=0;
g[i&1][0]=1;
for(int j=1;j<=m;j++) {
f[i&1][j]=max(max(f[i-1&1][j],f[i&1][j-1]),
f[i-1&1][j-1]+(s[i]==t[j]));
if(f[i&1][j]==f[i-1&1][j]) (g[i&1][j]+=g[i-1&1][j])%=mod;
if(f[i&1][j]==f[i&1][j-1]) (g[i&1][j]+=g[i&1][j-1])%=mod;
if(f[i&1][j]==f[i-1&1][j-1]&&s[i]!=t[j])
(g[i&1][j]+=mod-g[i-1&1][j-1])%=mod;
if(f[i&1][j]==f[i-1&1][j-1]+1&&s[i]==t[j])
(g[i&1][j]+=g[i-1&1][j-1])%=mod;
}
}
cout<<f[n&1][m]<<"
"<<g[n&1][m]<<endl;
}