洛谷 P2679 子串

题目连接

题目描述

有两个仅包含小写英文字母的字符串ABhtml

如今要从字符串A中取出k个互不重叠的非空子串,而后把这k个子串按照其在字符串A中出现的顺序依次链接起来获得一个新的字符串。请问有多少种方案能够使得这个新串与字符串B相等?数组

注意:子串取出的位置不一样也认为是不一样的方案。ide

题目分析

这道题是一道比较明显的动态规划。咱们先考虑划分状态。因为要从字符串A中取出k个互不重叠的非空子串,使它们链接起来与B相等,咱们容易想到记录在字符串A中已处理的长度、在字符串B中已处理的长度和已取出子串的个数。但这样仍是难以将状态转移方程推出来。咱们考虑再加入一维来表示对于字符串A的当前这一位是否被选择。这样咱们就能够开始推导方程式了。若是A的当前这一位不等于B的当前这一位,那么意味着它不可能被选择,因此它未被选择的方案数即为前一位选择或者不选择进当前当前子串两种方案数的总和,而被选择的方案数为零;若是等于,那么意味着它可选可不选,若选择,则其方案数为上一位选择进这个子串、选择进上个子串和不选择的方案数的总和,若不选择则与上一个状况相同。spa

这样,设fi,j,k,opt表示在字符串A中处理到第i个字符,字符串B中处理到第j个字符,当前选择的是第k个子串,选择当前字符的状况为opt(opt为0指当前字符选入,opt为1指当前字符不选入)的时候的方案总数,则有code

fi,j,k,0=∑{fi-1,j,l,1+fi-1,j,l,0},fi,j,k,1=A[i]==B[j]?∑{fi-1,j-1,l,1+fi-1,j-1,l-1,0+fi-1,j-1,l-1,1}:0(1<=l<=k)。
htm

但若是按照上面的方程,数组须要开到200*200*200*2,显然是不可能的。咱们注意到,对于第一维,其实只用到了i和i-1两个相邻的状态,因而咱们能够运用滚动数组,将第一维所需空间滚动成2,空间就没有问题了。blog

代码

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 int n,m,k,f[2][201][201][2];
 6 char a[1001],b[201];
 7 const int mod=1000000007;
 8 int main()
 9 {
10     scanf("%d%d%d%s%s",&n,&m,&k,a+1,b+1);
11     f[1][0][0][0]=f[0][0][0][0]=1;
12     for(int i=1;i<=n;++i)
13         for(int j=1;j<=m;++j)
14             for(int l=1;l<=k;++l)
15             {
16                 f[i&1][j][l][0]=(f[i+1&1][j][l][1]+f[i+1&1][j][l][0])%mod;
17                 f[i&1][j][l][1]=a[i]==b[j]?((f[i+1&1][j-1][l][1]+f[i+1&1][j-1][l-1][0])%mod+f[i+1&1][j-1][l-1][1])%mod:0;
18             }
19     printf("%d",(f[n&1][m][k][1]+f[n&1][m][k][0])%mod);
20     return 0;
21 }
子串
相关文章
相关标签/搜索