擴展kmp入門+比賽模板


https://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html 參考了這個ppt 理解起來還是有點費勁的(還是推薦一下這個課件 里面概念和思路給的比較全)

關鍵點 在extend[1...k]都已經求出來的情況下,求extend[k]。

 

關鍵利用s中有一部分和t相等。extend[k+1]的長度<=(s和t相等部分長度時候) extend[k+1]=next[k-a+1];

否者超出的部分要一一匹配並更新,a,p;

上個板子:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define mt(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll extend[1000001];
ll Next[1000001];
ll min(ll x,ll y)
{
    if(x>y) return y;
    return x;
}
void getNext(string t)
{
    mt(Next);
    ll len=t.length();
    Next[0]=len;
    ll a,p;
    a=1;
    while( a<len && t[a]==t[a-1]) a++; // 求出長度為1的時候 解為多少 
    Next[1]=a-1;
    a=1;
    for(ll i=2;i<len;i++) // 后續的按照算法來就好
    {
        p=a+Next[a]-1;
        if((i-1)+Next[i-a] < p ) Next[i]=Next[i-a];// 第一種情況 沒有超過等於的部分
        else // 超過的話就不好直接用next的定義 需要后續的遍歷
        {
            ll j = (p - i + 1) > 0 ? (p - i + 1) : 0;
            while(i + j < len && t[i+j] == t[j]) j++;
            Next[i]=j;
            a=i;
        }
    }
}
void exkmp(string s,string t) // s->extend  t->next
{
    getNext(t);
    ll a,p;//
    ll slen=s.length();
    ll tlen=t.length();
    a=p=0;
    ll len=min(s.length(),t.length());
    while(p<len && t[p]==s[p]) p++; // after
    extend[0]=p;
    for(ll i=1;i<slen;i++)
    {
        p=a+extend[a]-1; // update
        if( (i-1)+Next[i-a] < p) extend[i]=Next[i-a];
        else
        {
            ll j = (p - i + 1) > 0 ? (p - i + 1) : 0;
            while( j < tlen && i+j < slen && s[i + j] == t[j]) j++;
            extend[i]=j;
            a=i;
        }
    }
}
// 核心 一個起始位置a  一個最遠匹配位置p 然后Next 和 extend數組
int main()
{
    string s,t;// s->exkmp t->Next
    int Case;
    scanf("%d",&Case);
    while(Case--)
    {
        cin>>s>>t;
        exkmp(s,t);
       
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM