• Vijos1982 NOIP2015Day2T2 子串 substring 动态规划


    子串 (substring.cpp/c/pas)   题目链接

     

    【问题描述】
    有两个仅包含小写英文字母的字符串 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 取模 的结果。
    【输入输出样例 1】
    substring.in
    6 3 1
    aabaab
    aab
    substring.out
    2
    【输入输出样例 2】
    substring.in
    6 3 2
    aabaab
    aab
    substring.out
    7
    【输入输出样例 3】
    substring.in
    6 3 3
    aabaab
    aab
    substring.out
    7

    【题解】
    NOIP2015Day2T2
    一道好好的DP题
    我们用dp[i][j][k]表示在B串中匹配i个,在A串中匹配到的位置为j,共使用k个子串的方案总数,则dp[i][j][k]=Σdp[i-1][j'][k-1] +dp[i-1][j-1][k]
    那么,对于Σ可以用前缀和优化,这样的时间就可以卡进去了,但是空间还是要炸,所以我们采用滚动数组来优化空间即可。详见代码。

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=1000+5,M=200+5;
    const int mod=1e9+7;
    char s1[N],s2[M];
    int n,m,K;
    int dp[2][N][M],sum[2][N][M];
    //dp[i][j][k]=Σdp[i-1][j'][k-1](1<=j'<=j-1) +dp[i-1][j-1][k] 
    int main(){
        scanf("%d%d%d%s%s",&n,&m,&K,s1+1,s2+1);
        memset(dp,0,sizeof dp);
        memset(sum,0,sizeof sum);
        int I=0,J=1;
        for (int i=1;i<=n;i++){
            if (s2[1]==s1[i])
                dp[0][i][1]=1;
            sum[0][i][1]=sum[0][i-1][1]+dp[0][i][1];
        }
        for (int i=2;i<=m;i++,I^=1,J^=1){
            memset(dp[J],0,sizeof dp[J]);
            memset(sum[J],0,sizeof sum[J]);
            for (int j=1;j<=n;j++){
                if (s2[i]!=s1[j])
                    continue;
                for (int k=1;k<=K;k++)
                    if (j>=2)
                        dp[J][j][k]=(sum[I][j-1][k-1]+dp[I][j-1][k])%mod;
                    else
                        dp[J][j][k]=dp[I][j-1][k];
            }
            for (int k=1;k<=K;k++)
                for (int j=1;j<=n;j++)
                    sum[J][j][k]=(sum[J][j-1][k]+dp[J][j][k])%mod;
        }
        printf("%d",sum[I][n][K]);
        return 0;
    }

     

     



  • 相关阅读:
    GHOJ 683 小球
    GHOJ 682 图的m着色问题
    GHOJ 681 最佳调度问题
    YBT 最长公共子上升序列
    YBT 数的划分
    Educational Codeforces Round 68 (Rated for Div. 2) C
    马里奥项目中对象直接通讯小结
    Educational Codeforces Round 67 (Rated for Div. 2) C
    19新疆省赛总结
    Codeforces Round #560 div3 (C,D)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/NOIP2015Day2T2.html
Copyright © 2020-2023  润新知