• loj2424 「NOIP2015」子串[字符串DP]


    给定字符串 A,B,要求从 A 中取出互不重叠的 k 个非空子串,按照出现顺序拼起来后等于 B。求方案数。n ≤ 1000,m ≤ 200。


    主要是状态的转移。先设计出$f_{i,j,k}$表长度$B_j$分了$k$段很好想,但是发现并不容易转移。

    主要瓶颈在于当枚举了状态$f_{i,j,k}$ 的时候加入可以匹配($A_i=B_j$),怎么从前面$A_1sim A_{i-1}$里找出$k-1$块的$j-1$的方案数。(注意下面几行都是基于当前$A_i=B_j$这个条件的

    发现这个是可以叠加的,也就是$f_{i,j,k}$可以继承$f_{i-1,j,k}$的所有方案,那么只要不断继承,像滚雪球一样,求$f_{i,j,k}$直接就从$f{i-1,j-1,k-1}$来推就好了。

    第二个问题是,怎么处理拼接。如果枚举一段子串去匹配显然不太可做,发现拼接过程实际就是强制$i-1$处被选入了$k$个块内,然后和$i$位一合并,就完成了拼接。

    于是,为了知道$i-1$强制被选了的情况下有多少种$k$个块的方案,故再添加一维$0/1$表示是否被选。

    这下就可以推了。

    具体可以参见代码(我用了顺推格式)。注意滚动。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define dbg(x) cerr << #x << " = " << x <<endl
     7 using namespace std;
     8 typedef long long ll;
     9 typedef double db;
    10 typedef pair<int,int> pii;
    11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    16 template<typename T>inline T read(T&x){
    17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    19 }
    20 const int N=1000+5,M=200+5,P=1e9+7;
    21 int f[2][M][M][2],now;
    22 int n,m,l;
    23 char s[N],t[M];
    24 inline void add(int&A,int B){A+=B;A>=P&&(A-=P);}
    25 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    26     read(n),read(m),read(l);
    27     scanf("%s",s+1),scanf("%s",t+1);
    28     f[now=0][0][0][0]=1;
    29     for(register int i=0;i<n;++i,now^=1){
    30         for(register int j=0;j<=m;++j){
    31             for(register int k=0;k<=l;++k){
    32                 add(f[now^1][j][k][0],f[now][j][k][0]),add(f[now^1][j][k][0],f[now][j][k][1]);
    33                 if(s[i+1]==t[j+1])
    34                     add(f[now^1][j+1][k+1][1],f[now][j][k][0]),
    35                     add(f[now^1][j+1][k+1][1],f[now][j][k][1]),
    36                     add(f[now^1][j+1][k][1],f[now][j][k][1]);
    37             //    printf("%d %d %d %d %d
    ",i,j,k,f[now][j][k][0],f[now][j][k][1]);
    38                 f[now][j][k][0]=f[now][j][k][1]=0;
    39             }
    40         }
    41     }
    42     printf("%d
    ",(f[now][m][l][0]+f[now][m][l][1])%P);
    43     return 0;
    44 }
    View Code

    思路总结:1.继承方案,方便统计。2.子串问题中拼接可以设计0/1状态表示末尾有没有被选,这样可以直接和后面的东西合并

  • 相关阅读:
    在本地连接服务器上的mysql数据库
    js提取字符串中的数值
    下载安装mysql
    git最基础操作二(clone)
    点击页面出现富强、民主
    解决wepacke配置postcss-loader时autoprefixer失效问题
    li之间产生的间隙问题的解决方法
    webpack简单体验
    apply、call和bind
    remote Incorrect username or password ( access token)问题解决
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11556205.html
Copyright © 2020-2023  润新知