把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷2679】子串(动态规划)

点此看题面

大致题意: 让你从一个字符串中选择\(k\)个互不重叠的非空子串,使其按序拼接恰好组成另一个给定的字符串,求方案数。

动态规划

比较显然,这可以用动态规划解决。

考虑用\(f_{i,j,t,s}\)表示在第一个字符串前\(i\)位中选择\(t\)个子串组成第二个字符串前\(j\)位,且选/不选(1/0)第\(i\)的方案数,并用\(g_{i,j,t}\)记录\(f_{i,j,t,0}+f_{i,j,t,1}\)

则不难得出\(f_{i,j,t,0}=g_{i-1,j,t}\)

而对于\(f_{i,j,t,1}\)的转移,就需要分类讨论了:

\(s1_i!=s2_j\),显然该位不能选,故\(f_{i,j,t,1}=0\)

\(s1_i==s2_j\),则有两种情况:新选一个子串或不新选一个子串。即\(f_{i,j,t,1}=f_{i-1,j-1,t,1}+g_{i-1,j-1,t-1}\)

大致思路就是如此简单。

关于内存

等等,数组好像开不下?

\(hl666\)奆佬说:“滚存不就好了吗!”

于是这题就做完了。

代码

#include<bits/stdc++.h>
#define N 1000
#define M 200
#define XRY 1000000007
#define Inc(x,y) ((x+=(y))>=XRY&&(x-=XRY))
using namespace std;
inline int GetSum(int x,int y) {return Inc(x,y),x;}
int n,m,k,f[2][M+5][M+5][2],g[2][M+5][M+5];char s1[N+5],s2[M+5];
int main()
{
	register int i,j,t;
	scanf("%d%d%d%s%s",&n,&m,&k,s1,s2),g[0][0][0]=g[1][0][0]=f[0][0][0][0]=f[1][0][0][0]=1;//读入+初始化
	for(i=1;i<=n;++i) for(j=1;j<=m;++j) for(t=1;t<=k;++t)
	{
		f[i&1][j][t][0]=g[(i&1)^1][j][t],//转移f[i][j][t][0]
		f[i&1][j][t][1]=s1[i-1]^s2[j-1]?0:GetSum(f[(i&1)^1][j-1][t][1],g[(i&1)^1][j-1][t-1]),//转移f[i][j][t][1]
		g[i&1][j][t]=GetSum(f[i&1][j][t][0],f[i&1][j][t][1]);//计算g[i][j][t]
	}
	return printf("%d",g[n&1][m][k]),0;//输出答案
} 
posted @ 2018-11-10 22:12  TheLostWeak  阅读(329)  评论(0编辑  收藏  举报