求两个字符序列的最长公共子序列以及个数,\(n\leq 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]\neq 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]<<"\n"<<g[n&1][m]<<endl; }
来源:https://www.cnblogs.com/mollnn/p/12390071.html