2017 CCPC网络赛 hdu6153 KMP

来源:互联网 发布:猝死 知乎 编辑:程序博客网 时间:2024/06/03 19:19

题目链接
题意:给你连个字符串,s,t 求出t的所有后缀在s中出现的次数乘后缀的长度。
一开始想的后缀数组,tle,最后才知道是kmp
首先把s 和 他翻转一下,这是后就相当于求前缀了,然后求出t的next数组,然后对s跑kmp,跑的时候记录每一个长度匹配的次数,然后对于某个长度,如果他匹配了 比他小的也就匹配了,所以最后在类似求一个后缀和。
代码:

#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<string>#include<set>#include<map>#include<queue>#include<stack>#include<cstring>#define clr(x) memset(x,0,sizeof(x))using namespace std;#define LL long longconst LL N = 1000005;int _next[N];char s1[N];char s2[N];const LL MOD = 1e9+7;        LL cnt[N] = {0};int main(){    int t;    scanf("%d",&t);    while(t--)    {        clr(_next);        clr(cnt);        scanf("%s%s",s1,s2);        int len1 = strlen(s1);        int len2 = strlen(s2);        reverse(s1,s1+len1);        reverse(s2,s2+len2);        _next[1] = -1;        _next[0] = -1;        for(int i = 1,j=-1;i<len2;i++)        {            while(j!=-1 && s2[i]!=s2[j+1])            {                j = _next[j];            }            if(s2[i]==s2[j+1])            {                j++;            }            _next[i+1] = j;        }        for(int i = 0,j=-1;i<len1;i++)        {            while(j!=-1 && s1[i]!=s2[j+1])            {                j = _next[j];            }            if(s1[i]==s2[j+1])                j++;            if(j!=-1)                cnt[j+1]++;            if(j==len2-1)            {                j = _next[j+1];            }        }        for(int i = len1;i>0;i--)        {            if(_next[i]!=-1)            {                cnt[_next[i]+1] += cnt[i];            }        }        //cout << cnt[2] << endl;        LL ans = 0;        for(int i = 1;i<=len1;i++)        {            ans += cnt[i]*i;            ans%=MOD;        }        printf("%lld\n",ans);    }    return 0;}
原创粉丝点击