zoukankan      html  css  js  c++  java
  • P2679 子串

    题目描述

    有两个仅包含小写英文字母的字符串 A 和 B。

    现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 B 相等?

    注意:子串取出的位置不同也认为是不同的方案。

    输入格式

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

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

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

    输出格式

    一个整数,表示所求方案数。

    由于答案可能很大,所以这里要求输出答案对1000000007取模的结果。


        一道挺不错的dp,首先很容易想到用dp[i][j][k]表示从A串前i个字母选出k段与B串的前j项相同的方案数,显然:

    dp[i][0][0]=1;

        接下来考虑如何转移,首先,A[i]可以不参与匹配:

    dp[i][j][k]+=dp[i-1][j][k];

        其次,当(A[i]==B[j])时,我们可以把A[i]和B[j]单独匹配,也就是:

    dp[i][j][k]+=dp[i-1][j-1][k-1];

        也可以把A[i]强行接在A[i-1]后面,形成一整个串,所以我们还需要知道以A[i-1]结尾的串与B串前j-1位匹配的方案数,显然这个值为:

    dp[i-1][j-1][k]-dp[i-2][j-1][k];

        所以我们得到:

    dp[i][j][k]+=dp[i-1][j][k];

    dp[i][j][k]+=dp[i-1][j-1][k-1]+dp[i-1][j-1][k]-dp[i-2][j-1][k];(A[i]==B[j])

        算一下时间O(n*m*k)≈4e7,貌似可以接受,但是空间为320MB,考虑到每一层循环都只用到了i,i-1和i-2,所以我们只运用滚动数组需要保留三项即可。

     

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<string>
     5 #include<cmath>
     6 #define mod 1000000007
     7 #define maxn 2005
     8 using namespace std;
     9 
    10 int read()
    11 {
    12     int res=0,x=1;
    13     char c=getchar();
    14     while(c<'0'||c>'9')
    15     {
    16         if(c=='-')
    17         x=-1;
    18         c=getchar();
    19     }
    20     while(c>='0'&&c<='9')
    21     {
    22         res=res*10+(c-'0');
    23         c=getchar();
    24     }
    25     return res*x;
    26 }
    27 
    28 int n,m,t;
    29 long long f[3][205][205];
    30 char a[maxn],b[maxn];
    31 
    32 int main()
    33 {
    34     n=read();m=read();t=read();
    35     scanf("%s",a+1);scanf("%s",b+1);
    36     for(int i=1;i<=n;i++)
    37     {
    38         memset(f[i%3],0,sizeof(f[i%3]));
    39         f[0][0][0]=f[1][0][0]=f[2][0][0]=1;
    40         for(int j=1;j<=m;j++)
    41         for(int k=1;k<=min(j,t);k++)
    42         {
    43             if(a[i]==b[j])
    44             {
    45                 f[i%3][j][k]=(f[i%3][j][k]+f[(i-1)%3][j-1][k]+f[(i-1)%3][j-1][k-1])%mod;
    46                 if(i>=2) f[i%3][j][k]=((f[i%3][j][k]-f[(i-2)%3][j-1][k])%mod+mod)%mod;
    47             }
    48             f[i%3][j][k]=(f[i%3][j][k]+f[(i-1)%3][j][k])%mod;
    49         }
    50     }
    51     printf("%d
    ",f[n%3][m][t]);
    52     return 0;
    53 }
    View Code
  • 相关阅读:
    LeetCode Array Easy 414. Third Maximum Number
    LeetCode Linked List Medium 2. Add Two Numbers
    LeetCode Array Easy 283. Move Zeroes
    LeetCode Array Easy 268. Missing Number
    LeetCode Array Easy 219. Contains Duplicate II
    LeetCode Array Easy 217. Contains Duplicate
    LeetCode Array Easy 189. Rotate Array
    LeetCode Array Easy169. Majority Element
    LeetCode Array Medium 11. Container With Most Water
    LeetCode Array Easy 167. Two Sum II
  • 原文地址:https://www.cnblogs.com/snowy2002/p/11851427.html
Copyright © 2011-2022 走看看