A Secret HDU - 6153(扩展kmp)

时间:2021-02-03 21:10:44

题意要你求b串每一个后缀对a串的每一个后缀的匹配长度之和

 

将两个串倒过来

用这时的b串的前缀去匹配a的后缀

这时候所k处匹配的结果就是以k为终点,有最长可以匹配向后到extend[k]长度

对于每一个点等差数列求和 累加

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f

const int maxn=1e6+10;

int mod=1e9+7;

int nxt[maxn],extend[maxn];

int q;

char s[maxn],t[maxn];


void getnxt()
{
    int l=strlen(t);
    nxt[0]=l;
    int now=0;
    while(t[now]==t[now+1]&&now+1<l) now++;
    nxt[1]=now;
    int p0=1;//可以到达最远位置的i
    for(int i=2;i<l;i++)
    {
        if(i+nxt[i-p0]<nxt[p0]+p0)
            nxt[i]=nxt[i-p0];
        else
        {
            int now=nxt[p0]+p0-i;
            now=max(now,0);//这里是为了防止i>p的情况
            while(t[now]==t[i+now]&&i+now<l)
                now++;
            nxt[i]=now;
            p0=i;
        }
    }
}

void exkmp()
{
    getnxt();
    int now=0;
    int l=strlen(s);
    int l1=strlen(t);
    int lim=min(l,l1);
    while(s[now]==t[now]&&now<lim)
        now++;
    extend[0]=now;
    int p0=0;
    for(int i=1;i<l;i++)
    {
        if(i+nxt[i-p0]<extend[p0]+p0)
            extend[i]=nxt[i-p0];
        else
        {
            int now=extend[p0]+p0-i;
            now=max(now,0);
            while(t[now]==s[i+now]&&now<l1&&now+i<l)
                now++;
            extend[i]=now;
            p0=i;
        }
    }
}

int main()
{
    int mub;
    scanf("%d",&mub);
    while(mub--)
    {
        scanf("%s%s",s,t);
        int l=strlen(s);
        int l1=strlen(t);
        reverse(t,t+l1);
        reverse(s,s+l);
//        cout<<s<<endl;
//        cout<<t<<endl;
//        cout<<s<<endl;
//        cout<<t<<endl;
        mem(nxt,0);
        mem(extend,0);
        exkmp();
        ll ans=0;
        for(int i=0;i<l;i++)
        {
            ans=(ans+(1ll*extend[i]*(extend[i]+1)/2)%mod)%mod;           // ans+=extend[i];
        }
        printf("%d\n",ans);
        /*int l=t.size(),l1=s.size();
        for(int i=0;i<l;i++)
        {
            cout<<nxt[i]<<" ";
        }cout<<endl;
        for(int i=0;i<l1;i++)
        {
            cout<<extend[i]<<" ";
        }cout<<endl;*/
    }
    return 0;
}