扩展KMP 洛谷P5410 模板

题目链接:https://www.luogu.org/problem/P5410

题意:给两个字符串a,b,求b对a的每一个后缀的最大前缀长度

分析:扩展KMP(又称Z-algorithm算法)裸题

该博客讲解的比较好:https://www.luogu.org/blog/lc-2018-Canton/solution-p5410

但他有几个地方讲的有几个问题,主要在情况2里面

首先是一开始S[K+L]肯定是在p的后面,这个比较明显

然后情况二红蓝绿三条线的序列不是一样的,红绿还是一样的,但是蓝线就不等了,这个自己看一看

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;//单词间自行添加了符号,稍做扩大 
const ll inf=1e18;
#define meminf(a) memset(a,0x3f,sizeof(a))
#define mem0(a) memset(a,0,sizeof(a));
char a[maxn],b[maxn];
int nxt[maxn],extend[maxn];//nxt[i]代表b[i...len]和b的最大前缀长度,extend[i]代表a[i...len]和b的最大前缀长度 
void getnxt(){
    int len=strlen(b);
    nxt[0]=len;//nxt[0]就是原串情况下,自然就为len
    int now=0;
    while(b[now]==b[now+1]&&now+1<len) now++;
    nxt[1]=now;
    int p0=1;//p0是满足p0+nxt[p0]-1最大的点,一开始初始化为1 
    for(int i=2;i<len;i++){
        if(i+nxt[i-p0]<p0+nxt[p0]) nxt[i]=nxt[i-p0];
        //i相当于k+1,nxt[i-p0]相当于L(nxt[k-p0+2) 这里字符串是从0开始的,和博客里面从1开始的区别是少加一个1 
        else{
            int now=p0+nxt[p0]-i;
            now=max(now,0);//防止i在p的后面
            while(b[now]==b[i+now]&&i+now<len) now++;
            nxt[i]=now;
            p0=i;//更新p0 
        } 
    } 
}
void exkmp(){
    getnxt();
    int len=strlen(a);
    int now=0;
    while(a[now]==b[now]&&now<min(strlen(a),strlen(b))) now++;
    extend[0]=now;
    int p0=0;
    for(int i=1;i<len;i++){
        if(i+nxt[i-p0]<extend[p0]+p0) extend[i]=nxt[i-p0];
        else{
            int now=p0+extend[p0]-i;
            now=max(now,0);
            while(b[now]==a[i+now]&&now<strlen(b)&&i+now<len) now++;
            extend[i]=now;
            p0=i;
        }
    }  
}
int main(){
    scanf("%s%s",a,b);
    exkmp();
    for(int i=0;i<strlen(b);i++) printf("%d ",nxt[i]);
    putchar('\n');
    for(int i=0;i<strlen(a);i++) printf("%d ",extend[i]);
    putchar('\n');
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/qingjiuling/p/11391630.html