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

    Description

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

    Input

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

    Output

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

    Sample Input

    样例输入1:
    6 3 1
    aabaab
    aab

    样例输入2:
    6 3 2
    aabaab
    aab

    Sample Output

    样例输出1:
    2

    样例输出2:
    7

    Hint

    数据范围:
    对于第 1 组数据:1≤n≤500,1≤m≤50,k=1;
    对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=2;
    对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m;
    对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m;
    对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m;
    对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m。

    Solution

    这道题一看tm就是道DP题,而且第一感觉会很复杂

    设状态

    首先先来观察,我们设状态的话,要存储的应该有当前位置i,被匹配到的位置j,用了几个子串k(dp[i][j][k])

    但我们发现还有一个棘手的问题,如何判断当前的是一个独立的子串还是连接到前面的子串

    那么我们就要知道某一个位置是否被匹配,再加上一维[0/1]代表是否被匹配

    状态转移

    对于dp[i][j][k][0],他没被匹配,那匹配位置没变,子串个数没变,从i-1转移就是 dp[i-1][j][k][0]+dp[i-1][j][k][1]

    对于dp[i][j][k][1],前提条件就是A[i]==B[j],满足条件后我们发现,它可以分别从 (1)前一位没被匹配 (2)前一位被匹配,这个字符连接到前面一个子串 (3)前一位没被匹配,这一个字符单独成为一个子串,那么转移方程为dp[i-1][j-1][k-1][0]+dp[i-1][j-1][k-1][1]+dp[i-1][j-1][k][1]

    细节&优化

    边界条件:dp[i][1][1][0]=sigma(j=1->i-1)(A[j]==B[1])(显然可以累计,不需要每次求)  dp[i][1][1][1]=(A[i]==B[1])

    dp[1000][200][200][2]的空间是显然爆炸的,由于只要用到前一维,可以滚一滚第一维

    而每次计算完dp[i]后,要清空dp[i-1],否则会对dp[i+1]产生干扰(因为是滚动的)

    Code

     1 #include<set>
     2 #include<map>
     3 #include<stack>
     4 #include<queue>
     5 #include<cstdio>
     6 #include<cstring>
     7 #include<iostream>
     8 #include<algorithm>
     9 #define RG register int
    10 #define rep(i,a,b)    for(RG i=a;i<=b;i++)
    11 #define per(i,a,b)    for(RG i=a;i>=b;i--)
    12 #define ll long long
    13 #define inf (1<<30)
    14 #define maxm 205
    15 using namespace std;
    16 const ll mo=1000000007;
    17 int n,m,t,p,q;
    18 ll sum;
    19 ll dp[2][maxm][maxm][2];
    20 char A[1005],B[maxm];
    21 inline int read()
    22 {
    23     int x=0,f=1;char c=getchar();
    24     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    25     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    26     return x*f;
    27 }
    28 
    29 int main()
    30 {
    31     n=read(),m=read(),t=read();
    32     scanf("%s",A+1);scanf("%s",B+1);
    33     p=1,q=0;
    34     rep(i,1,n)
    35     {
    36         swap(p,q);
    37         dp[p][1][1][0]=sum;
    38         if(A[i]==B[1])    dp[p][1][1][1]=1,sum++;
    39         rep(j,2,m)
    40             rep(k,1,t)
    41             {
    42                 if(A[i]==B[j])    (dp[p][j][k][1]=(dp[q][j-1][k-1][0]+dp[q][j-1][k][1])%mo+dp[q][j-1][k-1][1])%=mo;            
    43                 dp[p][j][k][0]=(dp[q][j][k][0]+dp[q][j][k][1])%mo;
    44             }
    45        rep(j,1,m)    rep(k,1,t)    dp[q][j][k][0]=dp[q][j][k][1]=0;
    46     }
    47     cout<<(dp[p][m][t][0]+dp[p][m][t][1])%mo;
    48     return 0;
    49 }
    View Code
  • 相关阅读:
    Leetcode 349. Intersection of Two Arrays
    hdu 1016 Prime Ring Problem
    map 树木品种
    油田合并
    函数学习
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 102. Binary Tree Level Order Traversal
    Leetcode 101. Symmetric Tree
    poj 2524 Ubiquitous Religions(宗教信仰)
    pat 1009. 说反话 (20)
  • 原文地址:https://www.cnblogs.com/ibilllee/p/7726140.html
Copyright © 2011-2022 走看看