zoukankan      html  css  js  c++  java
  • 【NOIP2015】 Day2 T2 字串 (多维动归)

    2018-09-12

    原题传送门(洛谷)https://www.luogu.org/problemnew/show/P2679


    模拟考试的时候完全没有想到 正确的DP方程呢 

    本来写了一个大致是对的转移方程 结果算了一下空间 大概不够 就放弃了(第一维可以滚动 掉的啊喂 傻孩子啊) 愣是写了50分暴力

    下面是五十分的原代码

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<cstring>
     6 
     7 #define For(i,a,b) for(register int i=a;i<=b;++i)
     8 #define Dwn(i,a,b) for(register int i=a;i>=b;--i)
     9 #define Re register
    10 
    11 
    12 using namespace std;
    13 const int md=1e9+7;
    14 
    15 int na,nb,kx;
    16 string As,Bs;
    17 int sum=0;
    18 char c[60];
    19 int cf[60];
    20 
    21 int main(){
    22 //    freopen("ex2.in","r",stdin);
    23     freopen("substring.in","r",stdin);
    24     freopen("substring.out","w",stdout);
    25     cin>>na>>nb>>kx;
    26     cin>>As; cin>>Bs;
    27     if(kx==1){
    28         int px=0;
    29         while(1){
    30             int p=As.find(Bs,px);
    31             if(p==-1)break;
    32             sum++; px=p+1;
    33             if(sum>=md)sum%=md;
    34         }
    35         cout<<sum%md<<endl; return 0;
    36     }
    37     if(kx==2){
    38         string s1,s2;
    39         For(i,0,nb-2){
    40             s1=""; s2="";
    41             For(j,0,i)s1=s1+Bs[j];
    42             For(j,i+1,nb-1)s2=s2+Bs[j];
    43         //    cout<<s1<<" "<<s2<<" "<<sum<<endl;
    44             
    45             int px1,px2;
    46             int sum2=0;
    47             px1=px2=0;
    48             
    49             while(1){
    50                 int p1=As.find(s1,px1);
    51                 if(p1==-1)break;
    52                 sum2=0;
    53                 px2=p1+s1.size();
    54                 if(p1>na-1)break;
    55                 while(1){
    56                     int p2=As.find(s2,px2);
    57                     if(p2==-1)break;
    58                     sum2++; px2=p2+1;
    59                     if(sum2>=md)sum2%=md;
    60                 }
    61                 sum+=sum2;    if(sum>=md)sum%=md;
    62                 px1=p1+1;
    63             }
    64         }
    65         cout<<sum%md<<endl;
    66         return 0;
    67     }
    68     if(kx==nb){
    69         For(i,0,nb-1)c[i+1]=Bs[i],cf[i+1]=0;
    70         For(i,0,na-1){
    71             char ac=As[i];
    72             Dwn(j,nb,1){
    73                 if(ac==c[j]){
    74                     if(j==1)cf[j]++;
    75                     else cf[j]+=cf[j-1];
    76                     cf[j]%=md;
    77                 }
    78             }
    79         }
    80         sum=cf[nb]%md;
    81         cout<<sum<<endl;
    82         return 0;
    83     }
    84 }

    当k=1,(即只能分一个字串) 直接s.find()去搜就好了

    当k=2,(即分两个字串)还是暴力用find()去搜

    然后 当k=m (即与B串等长)想了一个挺巧妙的方法。。 用 cf[i] 数组表示此时的B串前 i 位的方案数  按顺序 考虑 A串的一个字符 

    从后往前枚举 i  当 A[j]== B[i]  cf[i]+=cf[i-1]  (算了算了都是暴力 不看也罢


    正确 方法 

    多维动归 !

    用我们 奥赛教练的话来说就是

            每次只要一考到 多维动归 我就替学生捏一把汗 这道题是能否拿到绝对高分的关键!!

    然鹅 模拟测试时我没做出来呢

    好了 下面正经写题解

    DP数组  f[i][j][k][0/1] 表示A的前i位 B的前j位 用了k个字串 A的第i个字串是否使用的方案数

    那么我们很容易就可以得到转移方程

       A[i]==B[j]

          1. 不取(0)f[i][j][k][0] <-- f[i-1][j][k][0] + f[i-1][j][k][1]

         2. 取  (1)f[i][j][k][1] <-- f[i-1][j-1][k][1] (与前方字符连成一个字串)+ f[i-1][j-1][k-1][1](自己单独另起一串)+ f[i-1][j-1][k-1][0]

      A[i]!=B[j]

          1. 不取(0)f[i][j][k][0] <-- f[i-1][j][k][0] + f[i-1][j][k][1]

          2. 取 显然只能等于 0

    初始边界 所有的 f[i][0][0][0]=1 

    然后愉快地把第一维 i 用滚动数组滚掉即可 

    复杂度 O(nmk)

    附上代码

     1 // luogu-judger-enable-o2
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 
     8 #define For(i,a,b) for(register int i=a;i<=b;++i)
     9 #define Re register
    10 using namespace std;
    11 const int Na=1e3+10,Nb=210;
    12 const int md=1e9+7;
    13 long long f[2][Nb][Nb][2];
    14 char A[Na],B[Nb];
    15 int na,nb,kx;
    16 int main(){
    17 //    freopen("substring9.in","r",stdin);
    18 //    freopen("substring.out","w",stdout);
    19     scanf("%d%d%d",&na,&nb,&kx);
    20     scanf("%s",A+1); scanf("%s",B+1);
    21     f[0][0][0][0]=f[1][0][0][0]=1;
    22     For(i,1,na){
    23         int now=i%2;
    24         For(j,1,nb) For(k,1,kx){
    25             if(A[i]==B[j]){
    26                 f[now][j][k][1]=(f[now^1][j-1][k][1]+f[now^1][j-1][k-1][1]+f[now^1][j-1][k-1][0])%md;
    27                 f[now][j][k][0]=(f[now^1][j][k][1]+f[now^1][j][k][0])%md;
    28             }else{
    29                 f[now][j][k][1]=0;
    30                 f[now][j][k][0]=(f[now^1][j][k][1]+f[now^1][j][k][0])%md;
    31             }
    32         }
    33     }
    34     long long fn=f[na%2][nb][kx][0]+f[na%2][nb][kx][1];
    35     cout<<fn%md<<endl;
    36     fclose(stdin); fclose(stdout);
    37     return 0;
    38     
    39 }
  • 相关阅读:
    在C#中使用消息队列RabbitMQ
    从url到页面经历了什么
    jsonp跨域远离
    DNS预处理
    一个架构师需要考虑的问题
    angular2和Vue2对比
    图片多的问题
    xinwenti
    xss和csrf
    ajax是什么
  • 原文地址:https://www.cnblogs.com/HLAUV/p/9727092.html
Copyright © 2011-2022 走看看