【HAOI2010】最长公共子序列

普通的LCS是经典的DP问题,那么如果加上方案数,则与最短路计数类似的

1.如果相同,就加上方案数

2.如果可以被更新,就重新统计方案数

但在这一题中,有一种特殊情况要考虑

如果一个子串,(i-1,j)和(i,j-1)都是由(i-1,j-1)转移过来,那么如果在更新f(i,j)时,就不可以用(i-1,j-1)继续累加,就应判定这是重复的,由容斥原理可得,应当减去这一方案数。

例外,此题内存限制严格,需用滚动数组

详细见代码

#include<bits/stdc++.h>
const int mod=1e8;
const int Maxn=5005;
int f[2][Maxn],sum[2][Maxn];
char s1[Maxn],s2[Maxn]; 
using namespace std;
inline int read(){
    char c=getchar();int fh=0;
    while(!isdigit(c))c=getchar();
    while(isdigit(c))fh=(fh<<1)+(fh<<3)+(c^48),c=getchar();
    return fh;
}
int main(){
    cin>>s1+1>>s2+1;
    int l1=strlen(s1+1)-1,l2=strlen(s2+1)-1;
    sum[0][0]=1;
    for(int i=1;i<=l2;++i)sum[0][i]=1;//初始化方案数
    for(int i=1;i<=l1;++i){
     sum[i&1][0]=1;
     for(int j=1;j<=l2;++j){
        f[i&1][j]=f[(i-1)&1][j];sum[i&1][j]=sum[(i-1)&1][j];//考虑(i-1,j)的情况
        if(f[i&1][(j-1)]>f[i&1][j])f[i&1][j]=f[i&1][(j-1)],sum[i&1][j]=sum[i&1][j-1];//i,j-1的情况>就更新
        else if(f[i&1][j-1]==f[i&1][j])sum[i&1][j]=(sum[i&1][j]+sum[i&1][j-1])%mod;//=就累加
        if(s1[i]==s2[j]){
          if(f[i&1][j]<f[(i-1)&1][j-1]+1)f[i&1][j]=f[(i-1)&1][j-1]+1,sum[i&1][j]=sum[(i-1)&1][j-1];
          else if(f[i&1][j]==f[(i-1)&1][j-1]+1)sum[i&1][j]=(sum[i&1][j]+sum[(i-1)&1][j-1])%mod;//同理
        }
        else{
          if(f[i&1][j]<f[(i-1)&1][j-1])f[i&1][j]=f[(i-1)&1][j-1],sum[i&1][j]=sum[(i-1)&1][j-1];
          else if(f[i&1][j]==f[(i-1)&1][j-1])sum[i&1][j]=(sum[i&1][j]-sum[(i-1)&1][j-1]+mod)%mod;//特殊情况,需要去重
        }
     }
    }
    cout<<f[l1&1][l2]<<endl<<sum[l1&1][l2]<<endl;
}

 

posted @ 2019-10-08 21:57  Coder_cjh  阅读(127)  评论(0编辑  收藏  举报