zoukankan      html  css  js  c++  java
  • DP × KMP

    几道用到KMP的DP题:

    hdu 5763    hdu 3689    hdu 3336    codeforces 494B    codevs 3945

    关于KMP的nx数组:

    如果在本文中看见了nx[]指的是所谓“成功指针”,或者getnx()函数跟本人之前的板子写的不一样......

    都是因为求nx数组有两种方法!!!

    详情请阅本人的另一篇文章:关于KMP算法的重大发现

    好了我们进入正题~

    一道一道来~

    hdu 5763  Another Meaning

    题意及样例:原题链接

    设第一个串为A,长为n;第二个串为B,长为L

    从1到n计算1~k能代表的意思的数量f[k]

    如果A[k-L+1,k]==B

    则f[k]=f[k-L]+f[k-1]

    否则f[k]=f[k-1]

    判断A[k-L+1,k]是否与B匹配就要靠KMP了

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mod 1000000007
     5 using namespace std;
     6 
     7 int t,al,bl;
     8 char a[100005];
     9 char b[100005];
    10 int nx[100005];
    11 int fl[100005];
    12 int f[100005]; 
    13 
    14 void getnx()
    15 {
    16     nx[1]=0;
    17     for(int i=2,j=1;i<=bl;)
    18     {
    19         nx[i]=j;
    20         while(j&&b[j]!=b[i])j=nx[j];
    21         j++,i++;
    22     }
    23 }
    24 
    25 void kmp()
    26 {
    27     for(int i=1,j=1;i<=al;)
    28     {
    29         while(j&&b[j]!=a[i])j=nx[j];
    30         if(j==bl)
    31         {
    32             fl[i]=1;
    33             j=nx[j];
    34         }
    35         else j++,i++;
    36     }
    37 }
    38 
    39 int main()
    40 {
    41     scanf("%d",&t);
    42     for(int cs=1;cs<=t;cs++)
    43     {
    44         memset(a,0,sizeof(a));
    45         memset(b,0,sizeof(b));
    46         memset(fl,0,sizeof(fl));
    47         scanf("%s",a+1);
    48         scanf("%s",b+1);
    49         al=strlen(a+1);
    50         bl=strlen(b+1);
    51         getnx();
    52         kmp();
    53         f[0]=1;
    54         for(int i=1;i<=al;i++)
    55         {
    56             if(fl[i])f[i]=(f[i-1]+f[i-bl])%mod;
    57             else f[i]=f[i-1];
    58         }
    59         printf("Case #%d: %d
    ",cs,f[al]);
    60     }
    61     return 0;
    62 }
    hdu 5763 Another Meaning

    hdu 3689  Infinite monkey theorem

    题目传送门

    概率DP,不一定一出错就要重头开始打。用nx[ ]数组转移,避免字符的浪费。

    这里的nx[ ]数组指的是成功指针......(玄学)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 int n,m,len;
     7 double p[30];
     8 char s[15];
     9 char key[30];
    10 int nx[15];
    11 double f[1005][15];
    12 
    13 void getnx()
    14 {
    15     nx[1]=0;
    16     for(int i=2,j=0;i<=len;i++)
    17     {
    18         while(j&&s[i]!=s[j+1])j=nx[j];
    19         if(s[j+1]==s[i])j++;
    20         nx[i]=j;
    21     }
    22 }
    23 
    24 int main()
    25 {
    26     while(true)
    27     {
    28         memset(nx,0,sizeof(nx));
    29         for(int i=1;i<=26;i++)p[i]=0.00;
    30         for(int i=0;i<=1001;i++)
    31         {
    32             for(int j=0;j<=11;j++)
    33             {
    34                 f[i][j]=0.00;
    35             }
    36         }
    37         scanf("%d%d",&n,&m);
    38         if(!n)return 0;
    39         for(int i=1;i<=n;i++)
    40         {
    41             char c[5];
    42             scanf("%s",c+1);
    43             key[i]=c[1];
    44             scanf("%lf",&p[i]);
    45         }
    46         scanf("%s",s+1);
    47         len=strlen(s+1);
    48         getnx();
    49         f[0][0]=1.00;
    50         for(int i=1;i<=m;i++)
    51         {
    52             for(int j=0;j<len;j++)
    53             {
    54                 for(int k=1;k<=n;k++)
    55                 {
    56                     int ps=j;
    57                     while(ps&&s[ps+1]!=key[k])ps=nx[ps];
    58                     if(s[ps+1]==key[k])ps++;
    59                     f[i][ps]+=f[i-1][j]*p[k];
    60                 }
    61             }
    62         }
    63         double ans=0.00;
    64         for(int i=1;i<=m;i++)ans+=f[i][len];
    65         printf("%.2lf%%
    ",ans*100.00);
    66     }
    67 }
    hdu 3689 Infinite monkey theorem

    hdu 3336  Count the string

    题目传送门

    利用KMP中nx[ ]数组的性质。

    上代码。

     1 #include<cstdio>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 int t,n,len,f[200005],ans;
     6 char s[200005];
     7 int nx[200005];
     8 
     9 void getnx()
    10 {
    11     for(int i=1;i<n;i++)
    12     {
    13         int j=nx[i];
    14         while(j&&s[i]!=s[j]) j=nx[j];
    15         nx[i+1]= s[i]==s[j] ? j+1:0;
    16     }
    17 }
    18 int main()
    19 {
    20     scanf("%d",&t);
    21     while(t--)
    22     {
    23         scanf("%d",&n);
    24         scanf("%s",s);
    25         len=strlen(s);
    26         getnx();
    27         memset(f,0,sizeof(f));
    28         ans=0;
    29         for(int i=1;i<=n;i++)
    30         {
    31             f[i]=f[nx[i]]+1;
    32             ans+=f[i];
    33             f[i]%=10007;
    34             ans%=10007;
    35         }
    36         printf("%d
    ",ans);
    37     }
    38 }
    hdu 3336 Count the string

    CodeForces 494B Obsessive String

    题目传送门

    比较复杂......

    记录f[ ],f[ ]的前缀和s[ ],还有s[ ]的前缀和ss[ ] 。

    KMP用来匹配字符串。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mod 1000000007
     5 using namespace std;
     6 
     7 char a[100005],b[100005];
     8 int al,bl;
     9 int nx[100005];
    10 int fl[100005];
    11 int f[100005],s[100005],ss[100005];
    12 
    13 void getnx()
    14 {
    15     nx[1]=0;
    16     for(int i=2,j=1;i<=bl;)
    17     {
    18         nx[i]=j;
    19         while(j&&b[j]!=b[i])j=nx[j];
    20         i++,j++;
    21     }
    22 }
    23 
    24 void kmp()
    25 {
    26     for(int i=1,j=1;i<=al;)
    27     {
    28         while(j&&a[i]!=b[j])j=nx[j];
    29         if(j==bl)fl[i]=1,j=nx[j];
    30         else i++,j++;
    31     }
    32 }
    33 
    34 int main()
    35 {
    36     scanf("%s",a+1);
    37     al=strlen(a+1);
    38     scanf("%s",b+1);
    39     bl=strlen(b+1);
    40     getnx();
    41     kmp();
    42     for(int i=1;i<=al;i++)
    43     {
    44         if(fl[i])f[i]=(i-bl+1+ss[i-bl])%mod;
    45         else f[i]=f[i-1];
    46         s[i]=(s[i-1]+f[i])%mod;
    47         ss[i]=(ss[i-1]+s[i])%mod;
    48     }
    49     int ans=0;
    50     for(int i=1;i<=al;i++)ans=(ans+f[i])%mod;
    51     printf("%d",ans);
    52 }
    CodeForces 494B Obsessive String

    CODEVS 3945 完美拓印

    题目传送门

    当成字符串匹配......

    坑挺多的,各种方向都得匹配一次求出答案。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 int a[1000005],b[1000005],s1[1000005],s2[1000005],nx[1000005];
     7 int n,m,ans;
     8 
     9 void getnx()
    10 {
    11     nx[0]=nx[1]=0;
    12     for(int i=1;i<n;i++)
    13     {
    14         int j=nx[i];
    15         while(j&&s1[i]!=s1[j])j=nx[j];
    16         nx[i+1]=(s1[i]==s1[j]?j+1:0);
    17     }
    18 }
    19 
    20 int kmp()
    21 {
    22     getnx();
    23     int j=0,cnt=0;
    24     for(int i=0;i<m;i++)
    25     {
    26         while(j&&s2[i]!=s1[j])j=nx[j];
    27         if(s2[i]==s1[j])j++;
    28         if(j==n)cnt++,j=nx[j];
    29     }
    30     return cnt;
    31 }
    32 
    33 int main()
    34 {
    35     scanf("%d%d",&n,&m);
    36     for(int i=0;i<n;i++)scanf("%d",&a[i]);
    37     for(int i=0;i<m;i++)scanf("%d",&b[i]);
    38     if(n==1)
    39     {
    40         printf("%d
    ",m<<2);
    41         return 0;
    42     }
    43     n--; m--;
    44     for(int i=0;i<n;i++)s1[i]=a[i+1]-a[i];
    45     for(int i=0;i<m;i++)s2[i]=b[i+1]-b[i]; 
    46     ans+=kmp();
    47     for(int i=0;i<n;i++)s1[i]=a[n-i]-a[n-i-1];
    48     ans+=kmp();
    49     for(int i=0;i<n;i++)s1[i]=0;
    50     ans+=2*kmp();
    51     printf("%d",ans);
    52     return 0;
    53 }
    CODEVS 3945 完美拓印

    结束了。

    最后顺便说,有些字符串匹配的题可以用hash做。

    这样可以偷懒,不用写KMP

    好吧还是乖乖背KMP板子吧。

    溜了。

  • 相关阅读:
    Stupid Tower Defense
    Lifting the Stone
    城市地平线
    BestCoder Sequence
    Miaomiao's Geometry
    Rating
    Turn the pokers
    Peter's Hobby
    HTTP关键词收集
    HTTP出现前的协议
  • 原文地址:https://www.cnblogs.com/cervusy/p/9480259.html
Copyright © 2011-2022 走看看