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
  • 相关阅读:
    SQL Server 循环插入数据
    转:Visual Studio 打开程序提示仅我的代码怎么办
    DevExpress XAF 访问当前视图中选定的对象
    DevExpress安装
    待定位的小bug
    easyui datagrid的toolbar 按钮可以像linkbutton一样设置使能状态
    使用jquery同时设置两个对象的method为同一函数
    首页变黑白的办法
    关于jQueryEasyUI DateBox的基本使用
    好东西分享兼备忘
  • 原文地址:https://www.cnblogs.com/ibilllee/p/7726140.html
Copyright © 2011-2022 走看看