HDU 6153 A Secret KMP

来源:互联网 发布:快刀软件 编辑:程序博客网 时间:2024/06/05 06:26


传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6153

题意:给你两个串a,b 求b串的所有后缀在a串的出现次数*后缀串长度和

思路:反转两个串 把后缀变前缀 kmp统计前缀 注意 kmp统计时ababab 时遍历会存在大前缀串的前缀是 反转b的前缀 需要单独统计

code:

#include<bits/stdc++.h>using namespace std;typedef long long LL;const int mod = 1e9 + 7;const int maxn = 1e6 + 100;LL ans;char S[maxn], T[maxn];int slen,tlen;int nextk[maxn];void getnextk(){    int j = 0, k = -1;    nextk[0] = -1;    while(j < tlen)    {        if(k == -1 || T[j] == T[k]) nextk[++j] = ++k;        else                        k = nextk[k];    }}int f[maxn];void KMP_Count(){    if(slen == 1 && tlen == 1){ans = (S[0] == T[0]);return;}    getnextk();    int i, j = 0;    for(i = 0; i < slen; i++)    {        while(j > 0 && S[i] != T[j])        {            j = nextk[j];        }        if(S[i] == T[j]) j++;        f[j]++;        if(j == tlen) j = nextk[j];    }    for(int i=tlen;i>=1;i--) f[ nextk[i] ]+=f[i];///长度为i对于前缀是否有相同段    for(int i=tlen;i>=1;i--)    {        ans=(ans+(LL)f[i]*i%mod)%mod,f[i]=0;    }}int main(){    int t;    scanf("%d", &t);    for(int cas = 1; cas <= t; cas++)    {        scanf("%s", S);        slen = strlen(S);        reverse(S, S + slen);        scanf("%s", T);        tlen = strlen(T);        reverse(T, T + tlen);        ans = 0;        KMP_Count();        printf("%lld\n", ans);    }    return 0;}