前述:

之前写过扩展kmp的题,但记忆不太深刻又忘记了,自己的模板上也没解释,那么这里就写一下吧,弥补之前的懒惰。

初学者不建议看。

自我对扩展KMP的理解:     

        自我觉得扩展KMP与mannacher算法都差不多,都是利用之前已经计算过的地方,去获取一个已经计算过的长度,然后再暴力计算未计算的长度。而kmp与扩展kmp有很大的不同

EXkmp:s[i...k+i-1]与s[0...k-1]相等的最大的k  (普通kmp是以i为后缀的相同的最长前缀,而扩展kmp是i为前缀的最长前缀)


例题

洛谷例题:P5410 【模板】扩展 KMP

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
char a[maxn],b[maxn];
int exb[maxn],exkmp[maxn];
/*
EXkmp:s[i...k+i-1]与s[0...k-1]相等的最大的k  (普通kmp是以i为后缀的相同的最长前缀,而扩展kmp是i为前缀的最长前缀)
exb[i]:b[i...k+i-1]与b[0...k-1]相等的最大的k
exkmp[i]:a[i..k+i-1]与b[0..k-1]相同的最大的k
*/
void pre_kmp(char s[],int ls,int next[])//预处理字符串b的kmp
{
    int id,maxr;//最长扩展的i和延申的位置maxr
    next[0]=ls;
    id=-1,maxr=-1;
    for(int i=1;i<ls;++i)
    {
        int qs;//next[i]的值
        if(maxr-i+1<=0)//不在可以扩展的范围,那就自己先为0
            qs=0;
        else
            qs=min(maxr-i+1,next[i-id]);//可扩展,取min以防出边界
        while(i+qs<ls&&s[i+qs]==s[qs]) ++qs;//暴力扩展未知的
        next[i]=qs;
        if(qs+i-1>maxr){
            maxr=qs+i-1;
            id=i;
        }
    }
}
void EXkmp(char a[],int la,char b[],int lb,int next[],int exkmp[])
{
    pre_kmp(b,lb,next);
    int id=-1,maxr=-1;
    for(int i=0;i<la;++i){
        int qs;
        if(maxr-i+1<=0) qs=0;
        else qs=min(maxr-i+1,next[i-id]);
        while(i+qs<la && qs<lb && a[i+qs]==b[qs]) ++qs;
        exkmp[i]=qs;
        if(qs+i-1>maxr){
            maxr=qs+i-1;
            id=i;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>a>>b;
    int lb=strlen(b);
    int la=strlen(a);
    EXkmp(a,la,b,lb,exb,exkmp);
//    pre_kmp(b,lb,exb);
    for(int i=0;i<lb;++i)
        cout<<exb[i]<<" ";
    cout<<endl;
    for(int i=0;i<la;++i)
        cout<<exkmp[i]<<" ";
    cout<<endl;
    return 0;
}

hdu 6629:string matching

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
typedef long long ll;
char s[maxn];
ll exs[maxn];
void pre_kmp(char s[],ll ls,ll next[])//预处理字符串b的kmp
{
    ll id,maxr;//最长扩展的i和延申的位置maxr
    next[0]=ls;
    id=-1,maxr=-1;
    for(ll i=1; i<ls; ++i)
    {
        ll qs;//next[i]的值
        if(maxr-i+1<=0)//不在可以重用数据的范围
            qs=0;
        else
            qs=min(maxr-i+1,next[i-id]);//可扩展,取min以防出边界
        while(i+qs<ls&&s[i+qs]==s[qs]) ++qs;
        next[i]=qs;
        if(qs+i-1>maxr)
        {
            maxr=qs+i-1;
            id=i;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>s;
        ll ans=0;
        ll ls=strlen(s);
        pre_kmp(s,ls,exs);
        for(ll i=1; i<ls; ++i)
        {
            if(i+exs[i]==ls)
                ans+=exs[i];
            else
                ans+=exs[i]+1;
        }
        cout<<ans<<endl;
    }

    return 0;
}