hdu6153 A Secret (拓展KMP)

来源:互联网 发布:客户提醒软件 编辑:程序博客网 时间:2024/06/05 03:26

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6153

题意:

        给你两个串,求第二个串的所有后缀在第一个串中出现的次数,加上后缀自身的长度和。

解:

利用拓展KMP得到extend数组,可以知道第一个串的后缀部分与第二个串的最长公共前缀。

例如:

          sababataba  ex30301

在s:ababab中,与aba的最长公共前缀为3,那么,我们可以知道aba的各个后缀在ababa中的开头部分出现了一次。其后缀长度为3  2  1,那么可以算得3*(3+1)/2=6;

继续重复计算就能算出答案。

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#define mem(a,b) memset(a,b,sizeof(a))using namespace std;const int mod=1e9+7;const int maxn=1e6+5;typedef long long ll;char s[maxn],t[maxn];int next1[maxn],extend[maxn];ll cal(ll x){    return ((x%mod)*((x+1)%mod)/2)%mod;}void get_next(char *str){    int i=0,j,po,len=strlen(str);    next1[0]=len;    while(str[i]==str[i+1]&&i+1<len)    i++;    next1[1]=i;    po=1;    for(i=2;i<len;i++)    {        if(next1[i-po]+i<next1[po]+po)        next1[i]=next1[i-po];        else        {            j=next1[po]+po-i;            if(j<0)j=0;            while(i+j<len&&str[j]==str[j+i])            j++;            next1[i]=j;            po=i;        }    }}void ex_kmp(char *s1,char *s2){    int i=0,j,po,len=strlen(s1),l2=strlen(s2);    get_next(s2);//计算子串的next数组    while(s1[i]==s2[i]&&i<l2&&i<len)//计算ex[0]    i++;    extend[0]=i;    po=0;//初始化po的位置    for(i=1;i<len;i++)    {        if(next1[i-po]+i<extend[po]+po)//第一种情况,直接可以得到ex[i]的值        extend[i]=next1[i-po];        else//第二种情况,要继续匹配才能得到ex[i]的值        {            j=extend[po]+po-i;            if(j<0)j=0;//如果i>ex[po]+po则要从头开始匹配            while(i+j<len&&j<l2&&s1[j+i]==s2[j])//计算ex[i]            j++;            extend[i]=j;            po=i;//更新po的位置        }    }}int main(){    int n;    scanf("%d",&n);    while(n--)    {        scanf("%s",s);        scanf("%s",t);        int tl=strlen(t),sl=strlen(s);        reverse(t,t+tl);        reverse(s,s+sl);        mem(next1,0);mem(extend,0);        ex_kmp(s,t);        ll ans=0;        for(int i=0;i<sl;i++)        {            //cout<<extend[i]<<" ";            if(extend[i])            ans=(ans+cal(extend[i])%mod)%mod;        }        //cout<<endl;        printf("%d\n",ans%mod);    }    return 0;}



原创粉丝点击