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
", ans[cur^1][m][k]);
	return 0;
}
原文地址:https://www.cnblogs.com/santiego/p/11437162.html