这题目第一眼扫过去就是DP,状态的表示熟练的人也不能想出来用$f[i,j,k]$表示当$A$匹配到前$i$位,$B$字符串匹配到$j$位,将$A$序列分成$k$段时候所能得到的数量。

总共有两种情况:
一:$i$这一位不与$j$匹配,即用前$i-1$去匹配$B$的前$j$位;二:$i$这一位与$i$前几位能与$B$的$j$这一位与其前几位一起匹配,作为一个单独的段(也就是有相同的后缀)。那么就有$f[i,j,k]=f[i-1][j][k]$(不匹配)$+\sum_{L}f[i-L-1][j-L-1][k-1]$(满足$A[i-L..i]=B[j-L..j]$,也就是所说的一起匹配)。

那么注意好初始化不难写出一个朴素的代码:

for(int i=0;i<=n;++i) f[i][0][0]=1;
for(int i=1;i<=n;i++){
    for(int j=1;j<=m && j<=i;j++){
        for(int p=1;p<=k && p<=j;p++){
            f[i][j][p]+=f[i-1][j][p];
            for(int l=0;l<i && l<j && A[i-l]==B[j-l];l++)
                f[i][j][p]+=f[i-l-1][j-l-1][p-1];
        }
    }
}

可惜,这样写会挂掉,时间和空间上都是。先考虑时间上的优化,可以优化的地方只剩下循环找一起匹配的段哪里了。我们想如果$A[i-L..i]=B[j-L..j]$的话,那么$f[i-1,j-1,k]$是不是保存了求$\sum_{L}f[i-L-1][j-L-1][k-1]$的那一段呢?(因为就相当于$A[i-1..i]$与$B[j-1..j]$一起匹配进去然后算)。

但是如果这样简单的改一下代码是不行的:

for(int i=0;i<=n;++i) f[i][0][0]=1;
for(int i=1;i<=n;i++){
    for(int j=1;j<=m && j<=i;j++){
        for(int p=1;p<=k;p++){
            f[i][j][p]+=f[i-1][j][p];
            if(A[i]==B[j]){
                f[i][j][p]+=f[i-1][j-1][p-1];
                   if(A[i-1]==B[j-1])
                       f[i][j][p]+=f[i-1][j-1][p];
            }
        }
    }
}

因为这里的$f$数组保存的信息不一定能构成连续,它也会保存前面不能连续匹配的数据,比如这组数据:

6 3 2
aabaab
aab
按照上面代码跑出来的$f[4,1,1]=3$这本身没错,但是看$f[5,2,2]=f[4,2,2]+f[4,1,0]+f[4,1,1]=1+0+3=4$,显然有误。仔细思考就会发现我们可以新建一个数组$g$,当$A[i]!=B[j]$的时候把$g$置为$0$,当$A[i]=B[j]$的时候令$g[i][j][k]=g[i-1][j-1][k]$(和前面连续的一同构成这第k段)$+f[i-1][j-1][k-1]$(单独构成第k段),而$f[i][j][k]=g[i][j][k]+f[i-1][j][k]$就行了。

然后就是空间的优化了,像背包一样把第一维省略掉,第二位倒序循环就ok了。

最后附上代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1005,M=205,mod=1000000007;
typedef long long ll;

char A[N],B[N];
ll f[M][M],g[M][M];
int n,m,k;

int main(){
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s",A+1);
    scanf("%s",B+1);
    f[0][0]=1;
    for (int i=1;i<=n;i++){
        for(int j=min(m,i);j>=1;j--) {
            for(int p=1;p<=k && p<=j;p++) {
                if(A[i]==B[j])  g[j][p]=(g[j-1][p]+f[j-1][p-1])%mod;
                else g[j][p]=0;
                f[j][p]=(g[j][p]+f[j][p])%mod;
            }
        }
    }
    printf("%lld",f[m][k]%mod);
    return 0;
}
01-31 23:02
查看更多