• 子串


    【题目描述】

    有两个仅包含小写英文字母的字符串A和B。现在要从字符串A中取出k个互不重叠的非空子串,然后把这k个子串按照其在字符串A中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串B相等?注意:子串取出的位置不同也认为是不同的方案。

    【输入描述】

    第一行是三个正整数n,m,k,分别表示字符串A的长度,字符串B的长度,以及问题描述中所提到的k,每两个整数之间用一个空格隔开。 

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

    【输出描述】

    输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对1,000,000,007取模的结果。

    【样例输入】

    样例1:

    6 3 1 

    aabaab

    aab

    样例2:

    6 3 2

    aabaab

    aab

    样例3:

    6 3 3 

    aabaab

    aab 

    【样例输出】

    样例1:

    2

    样例2:

    7

    样例3:

    7

    【数据范围及提示】

    1 ≤ n ≤ 1000,1 ≤ m ≤ 200,1 ≤ k ≤ m。

    蒟蒻的70分普通解法:

    源代码:
    
    #include<cstdio>
    #include<algorithm>
    #define INF 1000000007
    using namespace std;
    int m,n,k,f[1001][201][201][2];
    char s1[1001],s2[201];
    int main()
    {
        scanf("%d%d%d%s%s",&n,&m,&k,s1,s2);
        for (int a=0;a<=n;a++) //边界处理。
          f[a][0][0][0]=1;
        for (int a=1;a<=n;a++)
          for (int b=1;b<=m;b++)
            if (s1[a-1]==s2[b-1])
              for (int c=1;c<=min(k,b);c++) //注意循环结束条件。
              {
                  f[a][b][c][1]=(f[a-1][b-1][c-1][0]+f[a-1][b-1][c][1])%INF;
                  f[a][b][c][0]=(f[a-1][b][c][0]+f[a][b][c][1])%INF;
              }
            else
              for (int c=1;c<=min(k,b);c++)
                f[a][b][c][0]=f[a-1][b][c][0];
        printf("%d",f[n][m][k][0]);
        return 0;
    }
    
    /*
        此题只应天上有,人间能得几回闻。 ——某犇
        确实是一道好题,增加了我对DP的恐惧感。
        基本思想:(代码中以位置从0开始为准) 
            设f[a][b][c][1]表示:A串1-a,B串1-b,使用了c个子串,且选用A[a]的方案总数;
            设f[a][b][c][0]表示:A串1-a,B串1-b,使用了c个子串,包含选用和不选用A[a]的方案总数;
            由此可推得:
                f[a][b][c][0] = f[a][b][c][1]+f[a-1][b][c][0];
            
                f[a][b][c][1] = f[a-1][b-1][c-1][0]+f[a-1][b-1][c][1],(A[a]=B[b])
                              = 0,(A[a]≠B[b]);
    */

    滚动数组优化正解:

    源代码:
    
    #include<cstdio>
    #include<algorithm>
    #define INF 1000000007
    using namespace std;
    int m,n,k,f[201][201][2]={0};
    char s1[1001],s2[201];
    int main()
    {
        scanf("%d%d%d%s%s",&n,&m,&k,s1,s2);
        f[0][0][0]=1;
        for (int a=1;a<=n;a++)
          for (int b=m;b>0;b--)
            if (s1[a-1]==s2[b-1])
              for (int c=1;c<=min(k,b);c++)
              {
                  f[b][c][1]=(f[b-1][c-1][0]+f[b-1][c][1])%INF;
                  f[b][c][0]=(f[b][c][1]+f[b][c][0])%INF;
              }
            else
              for (int c=1;c<=min(k,b);c++) //某犇使用了memset()。
                  f[b][c][1]=0;
        printf("%d",f[m][k][0]);
        return 0;
    }
  • 相关阅读:
    WEB应用图片的格式,以及各自的特点和优化(一) by FungLeo
    Android---App Widget(五)
    【转】VS2010/MFC编程入门之八(对话框:创建对话框类和添加控件变量)
    【转】MFC中用CFile读取和写入文件2
    【转】VC中获取文件的相对路径和绝对路径
    【转】VC中对文件的读写
    【转】VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)
    【转】CString类型互转 int
    【转】Visual Studio快捷键汇总
    【转】Ubuntu下配置支持Windows访问的samba共享
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5656532.html
Copyright © 2020-2023  润新知