HDU 6153 A Secret

来源:互联网 发布:澳柯玛集团数据 编辑:程序博客网 时间:2024/06/05 03:06

题目链接

题目意思

给你两个字符串A,B,现在要你求B串的后缀在A串中出现的次数和后缀长度的乘积和为多少。

解题思路

扩展KMP模板题,将s和t串都逆序以后就变成了求前缀的问题了,扩展KMP求处从i位置开始的最长公共前缀存于数组,最后通过将数组的值不为0的进行一个等差数列和的和就可以了。

代码部分

#include <iostream>#include <string>#include <string.h>#include <cstring>#include <algorithm>using namespace std;const int maxn = 1e6 + 10;const int mod = 1e9 + 7;typedef long long ll;int cnt[maxn];char A[maxn],B[maxn];int Next[maxn],ex[maxn];ll add(ll n){    ll m=((n%mod)*((n+1)%mod)/2)%mod;    return m;}void kmp(char P[]){    int m=strlen(P);    Next[0]=m;    int j=0,k=1;    while(j+1<m&&P[j]==P[j+1]) j++;    Next[1]=j;    for(int i=2; i<m; i++)    {        int p=Next[k]+k-1;        int L=Next[i-k];        if(i+L<p+1) Next[i]=L;        else        {            j=max(0,p-i+1);            while(i+j<m&&P[i+j]==P[j])                j++;            Next[i]=j;            k=i;        }    }}void exkmp(char P[],char T[]){    int m=strlen(P),n=strlen(T);    kmp(P);    int j=0,k=0;    while(j<n&&j<m&&P[j]==T[j])        j++;    ex[0]=j;    for(int i=1; i<n; i++)    {        int p=ex[k]+k-1;        int L=Next[i-k];        if(i+L<p+1)            ex[i]=L;        else        {            j=max(0,p-i+1);            while(i+j<n&&j<m&&T[i+j]==P[j])                j++;            ex[i]=j;            k=i;        }    }}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%s%s",A,B);        int lenA=strlen(A);        int lenB=strlen(B);        reverse(A,A+lenA);        reverse(B,B+lenB);        kmp(B);        memset(Next,0,sizeof(Next));        memset(ex,0,sizeof(ex));        exkmp(B,A);        ll ans = 0;        for(int i=0;i<lenA;i++)        {            if(ex[i])                ans=(ans+add(ex[i])%mod)%mod;        }        printf("%lld\n",ans%mod);    }    return 0;}