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 }