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;
}
posted @ 2019-08-30 21:12  Santiego  阅读(91)  评论(0编辑  收藏  举报