扩展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;
}

 

posted @ 2017-08-21 15:35  猪突猛进!!!  阅读(1640)  评论(0编辑  收藏  举报