首先$LIS$显然:$f[i][j]=max(f[i][j-1],f[i-1][j],(a[i]==b[j])*f[i-1][j-1])$
考虑如何转移数量:
首先,不管$a[i]$是否等于$b[j]$,
都有$h[i][j]+=h[i-1][j]*(f[i][j]==f[i-1][j])+h[i][j-1]*(f[i][j]==f[i][j-1])$
然后讨论$LIS$中第三种转移:
如果$a[i]==b[j] && f[i][j]==f[i-1][j-1]+1$,有$h[i][j]+=h[i-1][j-1]$
而如果$a[i]!=b[j] && f[i][j]==f[i-1][j-1]$,有$h[i][j]-=h[i-1][j-1]$,此处是考虑$h[i-1][j]$与$h[i][j-1]$对答案的重复转移,所以要减去;
#include<cstdio> #include<iostream> #include<cstring> #define R register int using namespace std; namespace Fread { static char B[1<<15],*S=B,*D=B; #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++) inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } inline bool isempty(const char& ch) {return ch<=36||ch>=127;} inline void gs(char* s) {register char ch; while(isempty(ch=getchar())); do *s++=ch; while(!isempty(ch=getchar()));} }using Fread::g; using Fread::gs; const int N=500010,M=1E+8; int n,m; char s1[N],s2[N]; int f[2][N],h[2][N]; signed main() { gs(s1+1),gs(s2+1); R l1=strlen(s1+1)-1,l2=strlen(s2+1)-1; R c=0; for(R i=0;i<=l2;++i) h[c][i]=1; for(R i=1;i<=l1;++i) { c^=1; h[c][0]=1; for(R j=1;j<=l2;++j) { h[c][j]=0; f[c][j]=max(f[c^1][j],f[c][j-1]); if(s1[i]==s2[j]) f[c][j]=max(f[c][j],f[c^1][j-1]+1); if(f[c][j]==f[c^1][j]) h[c][j]+=h[c^1][j]; if(f[c][j]==f[c][j-1]) h[c][j]+=h[c][j-1]; if(s1[i]==s2[j]&&f[c][j]==f[c^1][j-1]+1) h[c][j]+=h[c^1][j-1]; if(s1[i]!=s2[j]&&f[c][j]==f[c^1][j-1]) h[c][j]-=h[c^1][j-1]; h[c][j]=(h[c][j]+M)%M; } } printf("%d %d ",f[c][l2],h[c][l2]); }
2019.07.11