zoukankan      html  css  js  c++  java
  • 【kmp或扩展kmp】HDU 6153 A Secret

    acm.hdu.edu.cn/showproblem.php?pid=6153

    【题意】

    • 给定字符串A和B,求B的所有后缀在A中出现次数与其长度的乘积之和
    • A和B的长度最大为1e6

    方法一:扩展kmp

    【思路】

    • 把A和B同时反转,相当于求B的所有前缀在A中出现次数与其长度的乘积之和
    • 换个角度,相当于A中每出现一个B的前缀,答案中就要加上该前缀的长度
    • 考虑A中每个位置对答案的贡献,A[i...lenA-1]与B的最长公共前缀是x,则B中的前缀B[0...1],B[0....2]...B[0....x]都在A中出现,那么答案就要加上x*(x+1)/2
    • 求S中的每个后缀与T的最长公共前缀用扩展KMP,时间复杂度是线性的

    【AC】

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const ll mod=1e9+7;
     5 const int maxn=1e6+2;
     6 char s[maxn];
     7 char t[maxn];
     8 int nxt[maxn];
     9 int extend[maxn];
    10 ll ans;
    11 
    12 void add(ll n)
    13 {
    14     ll tmp=((n%mod)*((n+1)%mod)/2)%mod;
    15     ans=(ans+tmp)%mod;
    16 }
    17 void pre_EKMP(char x[],int m,int nxt[])
    18 {
    19     nxt[0]=m;
    20     int j=0;
    21     while(j+1<m && x[j]==x[j+1]) j++;
    22     nxt[1]=j;
    23     int k=1;
    24     for(int i=2;i<m;i++)
    25     {
    26         int p=nxt[k]+k-1;
    27         int L=nxt[i-k];
    28         if(i+L<p+1) nxt[i]=L;
    29         else
    30         {
    31             j=max(0,p-i+1);
    32             while(i+j<m && x[i+j]==x[j]) j++;
    33             nxt[i]=j;
    34             k=i;
    35         }
    36     }
    37 }
    38 
    39 void EKMP(char x[],int m,char y[],int n,int nxt[],int extend[])
    40 {
    41     pre_EKMP(x,m,nxt);//子串 
    42     int j=0;
    43     while(j<n && j<m &&x[j]==y[j]) j++;
    44     extend[0]=j;
    45     int k=0;
    46     for(int i=1;i<n;i++)
    47     {
    48         int p=extend[k]+k-1;
    49         int L=nxt[i-k];
    50         if(i+L<p+1) extend[i]=L;
    51         else
    52         {
    53             j=max(0,p-i+1);
    54             while(i+j<n && j<m && y[i+j]==x[j]) j++;
    55             extend[i]=j;
    56             k=i;
    57         }
    58     }
    59 }
    60 
    61 int main()
    62 {
    63     int T;
    64     scanf("%d",&T);
    65     while(T--)
    66     {
    67         scanf("%s",s);
    68         scanf("%s",t);
    69         int ls=strlen(s);
    70         int lt=strlen(t);
    71         for(int i=0;i<ls/2;i++)
    72         {
    73             swap(s[i],s[ls-1-i]);
    74         }
    75         for(int i=0;i<lt/2;i++)
    76         {
    77             swap(t[i],t[lt-1-i]);
    78         }
    79         EKMP(t,lt,s,ls,nxt,extend);
    80         ans=0;
    81         for(int i=0;i<ls;i++)
    82         {
    83             add(extend[i]);
    84         }
    85         printf("%I64d
    ",ans);
    86     }
    87     return 0;
    88 } 
    扩展kmp

     方法二:巧用kmp的next数组

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn=1e6+2;
     5 ll id[maxn];
     6 char s[maxn];
     7 char t[maxn];
     8 int nxt[maxn];
     9 const ll mod=1e9+7;
    10 void kmp_pre(char x[],int m,int nxt[])
    11 {
    12     int i,j;
    13     j=nxt[0]=-1;
    14     i=0;
    15     while(i<m)
    16     {
    17         while(-1!=j && x[i]!=x[j]) j=nxt[j];
    18         nxt[++i]=++j;
    19     }
    20 }
    21 
    22 int kmp_count(char x[],int m,char y[],int n)
    23 {
    24     memset(id,0,sizeof(id));
    25     int i,j;
    26     ll ans=0;
    27     kmp_pre(x,m,nxt);
    28     i=j=0;
    29     while(i<n)
    30     {
    31         while(-1!=j && y[i]!=x[j]) 
    32             j=nxt[j];
    33         i++;
    34         j++;
    35         if(i>=n) break;
    36         //失配时记录当前匹配的最长前缀 
    37         if(y[i]!=x[j])
    38         {
    39             id[j]++;
    40         }
    41         if(j>=m)
    42             j=nxt[j];
    43     }
    44     //s的结尾出有一段和匹配的,由于i已经达到n没有记录,用t本身的nxt算出 
    45     while(j!=-1)
    46     {
    47         id[j]++;
    48         j=nxt[j];
    49     }
    50     for(int i=1;i<=m;i++)
    51     {
    52         if(id[i])
    53         {
    54             ans=(ans+(1ll*i*(i+1)/2)%mod*id[i]%mod)%mod;
    55         }
    56     }
    57     return ans;
    58 }
    59 int main()
    60 {
    61     int T;
    62     scanf("%d",&T);
    63     while(T--)
    64     {
    65         scanf("%s",s);
    66         scanf("%s",t);
    67         int ls=strlen(s);
    68         int lt=strlen(t);
    69         reverse(s,s+ls);
    70         reverse(t,t+lt);
    71         ll res=kmp_count(t,lt,s,ls);
    72         cout<<res<<endl;
    73     }
    74     return 0;
    75 }
    kmp
  • 相关阅读:
    设计模式开篇——7大设计原则
    MySQL MVCC专题
    Spring常考的面试题
    HashMap常考面试题
    Equals和==的比较
    高并发编程
    一文读懂JVM
    scala实现定时任务的方法
    PLAY2.6-SCALA(十二) 表单的处理
    PLAY2.6-SCALA(十一) 模板常用场景
  • 原文地址:https://www.cnblogs.com/itcsl/p/7400730.html
Copyright © 2011-2022 走看看