大致题意: 让你从一个字符串中选择(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;//输出答案
}