Noip 2015 senior 复赛 Day2 子串

Noip 2015 senior 复赛 Day2 T2

【问题描述】

有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重

叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一

个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出

的位置不同也认为是不同的方案。

【输入格式】

输入文件名为 substring.in。

第一行是三个正整数 n, m, k,分别表示字符串 A 的长度,字符串 B 的长度,以及问

题描述中所提到的 k,每两个整数之间用一个空格隔开。

第二行包含一个长度为 n 的字符串,表示字符串 A。

第三行包含一个长度为 m 的字符串,表示字符串 B。

【输出格式】

输出文件名为 substring.out。

输出共一行,包含一个整数,表示所求方案数。 由于答案可能很大,所以这里要求输

出答案对 1,000,000,007 取模的结果。

 

       这是一道DP类型的题目,状态转移方程还是比较好推的:

       如果两个串的字符不同:

       Element_program[k][i][j] = (Element_program[k][i-1][j-1] + Ultimate_program[k-1][i-1][j-1]) % mod;

       对于每一次的字符比较:

Ultimate_program[k][i][j] = (Ultimate_program[k][i-1][j] + Element_program[k][i][j]) % mod;

但是这样推出来的状态转移方程由于3维,所以空间是会爆掉的,只能保证前7个点(记得需要把数组开小点)。那么解决方法是什么呢,可以直接降维,只要你这方面比较强。还可以使用动态数组。

什么是动态数组呢?记得曾经一道求解二项式系数的题目吗?我们在求解的时候对于组合数是采用的杨辉三角,但是,数组是开不了n那么大的,所以我们采用只保存两层的方式。那么动态数组就是这样的思想,我们由于求解的问题只与n与n-1相关,所以我们也只保存这两层的数据,这样我们就能把3维降成两个2维的数组(也可以开dp[3][n][m])。

 

  

 1 #include<cstdio> //三维
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 #define N 1010
 8 #define M 205
 9 #define mod 1000000007 
10 
11 char first[N],second[M];
12 int n,m,part;
13 int Ultimate_program[M][N][M],Element_program[M][N][M];
14 
15 inline void ltsinit()
16 {
17     scanf("%d %d %d",&n,&m,&part);
18     scanf("%s",first);
19     scanf("%s",second);
20 }
21 
22 inline void Dynamic_programming()
23 {
24     Ultimate_program[0][0][0] = 1;
25     for(int i=1;i<=n;i++)
26     {
27         Ultimate_program[0][i][0] = 1;
28         for(int j=1;j<=m;j++)
29         {
30             for(int k=1;k<=part;k++)
31             {
32                 if(first[i-1] != second[j-1])
33                     Element_program[k][i][j] = 0;
34                 else
35                     Element_program[k][i][j] = (Element_program[k][i-1][j-1] + Ultimate_program[k-1][i-1][j-1]) % mod;
36                 
37                 Ultimate_program[k][i][j] = (Ultimate_program[k][i-1][j] + Element_program[k][i][j]) % mod;
38             }
39         }
40     }
41 }
42 
43 int main()
44 {
45 //    freopen("substring.in","r",stdin);
46 //    freopen("substring.out","w",stdout);
47     
48     ltsinit();
49     Dynamic_programming();
50     printf("%d",Ultimate_program[part][n][m]);
51     
52     return 0;
53 }

 

 1 #include<cstdio> //二维
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 #define N 1010
 8 #define M 205
 9 #define mod 1000000007 
10 
11 char first[N],second[M];
12 int n,m,part;
13 int Ultimate_program[M][M],Element_program[M][M];
14 
15 inline void ltsinit()
16 {
17     scanf("%d %d %d",&n,&m,&part);
18     scanf("%s",first);
19     scanf("%s",second);
20 }
21 
22 inline void Dynamic_programming()
23 {
24     Ultimate_program[0][0] = 1;
25     for(int i=1;i<=n;i++)
26     {
27 //        Ultimate_program[0][0] = 1;
28         for(int j=m;j>=1;j--)
29         {
30             for(int k=min(part,j);k>=1;k--)
31             {
32                 if(first[i-1] != second[j-1])
33                     Element_program[k][j] = 0;
34                 else
35                 {
36                     Element_program[k][j] = (Ultimate_program[k-1][j-1] + Element_program[k][j-1]) % mod;
37                     Ultimate_program[k][j] = (Ultimate_program[k][j] + Element_program[k][j]) % mod;
38                 }
39             }
40         }
41     }
42 }
43 
44 int main()
45 {
46 //    freopen("substring.in","r",stdin);
47 //    freopen("substring.out","w",stdout);
48     
49     ltsinit();
50     Dynamic_programming();
51     printf("%d",Ultimate_program[part][m]);
52     
53     return 0;
54 }

 

posted @ 2017-07-16 21:14  唯莫  阅读(249)  评论(0编辑  收藏  举报