P2679 子串 DP

P2679 子串 DP

从字符串A中取出\(k\)段子串,按原顺序拼接,问存在多少个方案使拼接的字符串与字符串B相同

淦,又是这种字符串dp

设状态\(ans[i][j][k]\)表示A串位置\(i\),B串位置\(j\),已取出\(k\)段字符串,不管当前位置\(i\)是否能匹配上的方案数,\(g[i][j][k]\)表示A串位置\(i\),B串位置\(j\),已取出\(k\)段字符串,当前A串位置\(i\)已匹配上B串位置\(j\)(即\(a[i]==b[j]\))的方案数。

状态转移:

if(a[i]==b[j]) // 如果匹配上了
    g[i][j][p]=(g[i-1][j-1][p]+ans[i-1][j-1][p-1])%MOD;
    // g[i-1][j-1][p] 表示与上一个匹配连在一起
    // ans[i-1][j-1][p-1] 以前的方案数
else g[i][j][p]=0;

ans[i][j][p]=(g[i][j][p]+ans[i-1][j][p])%MOD;   
// g[i][j][p] 现在新匹配上的
// ans[i-1][j][p] 以前的方案数

然后为了优化空间就上了滚动数组,见代码:

#include <cstdio>
#define MAXN 1010
#define MOD 1000000007
using namespace std;
int n,m,k;
int ans[3][MAXN][MAXN],g[3][MAXN][MAXN];
char a[MAXN],b[MAXN];
int main(){
    scanf("%d %d %d", &n, &m, &k);
    scanf("%s%s", a+1, b+1);
    int cur=1;
    ans[0][0][0]=1;
    for(int i=1;i<=n;++i){
        ans[cur][0][0]=1;
        for(register int j=1;j<=m;++j)
            for(register int p=1;p<=k;++p){
                if(a[i]==b[j]) g[cur][j][p]=(g[cur^1][j-1][p]+ans[cur^1][j-1][p-1])%MOD;
                else g[cur][j][p]=0;
                ans[cur][j][p]=(g[cur][j][p]+ans[cur^1][j][p])%MOD;
            }
        cur^=1;
    }
    printf("%d\n", ans[cur^1][m][k]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/santiego/p/11437162.html