zoukankan      html  css  js  c++  java
  • [DP][NOIP2015]子串

    子串

    题目描述

    有两个仅包含小写英文字母的字符串 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  取模 的结果。

    样例输入

    6 3 1
    aabaab
    aab

    样例输出

    2

    提示



    题解:

    从网上ctrl c + v来的你们不会介意的对吧(逃~

    “*那么记一下思路吧,这道题是要压缩的,它会卡空间的,要滚动数组。
    我们按照三维的来考虑,我们再记一个数组f[i][j][k]为选择第i位后的a串前i个b串前j个选择k个子串有几种组合方式
    s[i][j][k]是a串前i个b串前j个选择k个子串有几种组合方式,f,s数组的差别是一个选了第i个,一个不一定选了第i个
    然后和最长公共子串一样
    f数组的递推思路:要是a的第i位能够和b的第j位匹配上,我们选择第i位当一个串是一种情况,
    这个时候我们把s数组的s[i-1][j-1][k-1]转移过来就可以了,那么i-1显然也要和j-1匹配上才能多加上额外的一些情况,
    如果i-1和j-1都匹配不上就不能再往左延伸了,所以如果a[i]!=b[j]相当于一个公共子串被切断一样,f[i][j][k]=0
    所以:
    f[i][j][k]=f[i-1][j-1][k]+s[i-1][j-1][k-1] (a[i]==b[j])
    f[i][j][k]=0 (a[i]!=b[j])
    s数组的递推思路:当a[i]==b[j]时,我们可以选i也可以不选,我们加上f数组就好了和不选的情况s[i-1][j][k]就可以了,
    如果不相同那就肯定不选了,此时f数组为0,我们无需特判
    s[i][j][k]=f[i][j][k]+s[i-1][j][k]
    压缩的思路:由于我们的每次i都只与i-1有关,所以我们可以把第一维压缩掉,因为后面的j要用到j-1的情况,
    所以我们从后往前更新,k同理,也是从后往前,然后要控制范围是min(K,j)*”

    代码:

     1 #include<algorithm>
     2 #include<cstdio>
     3 
     4 int n, m, k;
     5 long long f[2][205][205], s[2][205][205];
     6 char a[1005], b[205];
     7 const int mod = 1000000007;
     8 
     9 int read(){
    10     int x = 0, f = 1; 
    11     char ch = getchar(); 
    12     while (ch < '0' || ch > '9') {
    13         if (ch == '-') {
    14             f = -1; 
    15         }
    16         ch = getchar(); 
    17     }
    18     while (ch >= '0' && ch <= '9') {
    19         x = x * 10 + ch - '0'; 
    20         ch = getchar(); 
    21     }
    22     return x * f; 
    23 }
    24 
    25 int main(){
    26     n = read(); 
    27     m = read(); 
    28     k = read(); 
    29     scanf("%s", a + 1);
    30     scanf("%s", b + 1);
    31     int now = 1, last = 0;
    32     f[0][0][0] = 1;
    33     for (int i = 1; i <= n; i++) {
    34         f[now][0][0] = 1;
    35         for (int j = 1; j <= m; j++) {
    36             for (int kk = 1; kk <= k; kk++) {
    37                 if (a[i] == b[j]) {
    38                     s[now][j][kk] = (s[last][j - 1][kk] + f[last][j - 1][kk - 1]) % mod;
    39                 }
    40                 else {
    41                     s[now][j][kk] = 0;
    42                 }
    43                 f[now][j][kk] = (f[last][j][kk] + s[now][j][kk]) % mod;
    44             }
    45         }
    46         std::swap(now, last);
    47     }
    48     printf("%lld
    ", f[last][m][k]);
    49     return 0;
    50 }
  • 相关阅读:
    angualrjs2教程
    需要关注的技术
    webstorm 2016
    Java内存泄露分析和解决方案及Windows自带查看工具
    2018-6-21-随笔-WEB应用程序
    2018-6-20-随笔-SQL Server中乱码
    2018年6月15日随笔--统计图
    2018-6-12随笔-类库
    2018-6-11随笔-返回值-密钥
    vs各种版本
  • 原文地址:https://www.cnblogs.com/GldHkkowo/p/8922033.html
Copyright © 2011-2022 走看看