哇通过看各种题解总算学懂了!!!发现$kmp$并没有那——么难理解哦$quq$

首先介绍最傻逼的暴力解法引入正题这个就懒得讲了没什么意思也没这时间,直接港$kmp$的思想趴

先举个$eg$这样方便理解一些,假如匹配串是$abaabbabaab$

随便港下

首先,我并不关心被匹配串,因为显然匹配串更灵活嘛,就只需要考虑匹配串

然后现在考虑,假如我匹配串从第1位到第i位都匹配成功了,然后到第$i+1$位失败了,怎么搞

肯定是往后移,但是直接移就太傻逼了就是暴力了嘛,我们考虑用已知条件推出来我们至少要移动到哪儿

然后现在还能给你个已经预处理过了的数组$nxt_i$,存的是从第$1$位到第$i$位,前缀后缀相等的最大长度

以我们举的$eg$解释下,那$nxt$就$=\{0,0,1,1,2,0,1,2,3,4,5\}$

那我们就可以发现,我们只需要往后移到第$i$位并从$nxt_i$位继续匹配就好了(这个还是显然的?下面还是详细解释下$quq$

$umm$还是,强行解释下$QAQ$假如我们在匹配的时候,$abaabbabaa$这一段都匹配了,然而到再后一位$b$的时候发现失配了,怎么办呢?

我们就看下$nxt$数组,发现最长的前后缀相等的长度为$3$,就是说开头的$abaa$和结尾的$abaa$是相同的嘛,而且在这一段的中间不可能移动更少的距离还能匹配的了(因为已经是最长的了鸭!

然后我们就继续从$abaa$的后一位$b$这里匹配看被匹配串能不能匹配上不能就继续跳$nxt$就好了!

然后大概理解了趴?还有一个就是,我们怎么求$nxt$呢?

就大概这么想:

其实也是利用已经获得的信息

这样的,假如我们现在已经匹配到了第$i$位,要求$nxt_{i+1}$了

如果$s_{i+1}=s_{nxt_i+1}$,当然就直接$++$咯,就是$nxt_{i+1}=nxt_i+1$,这个显然

那如果不相等怎么处理?

首先我们拿出最前面那一段$1-nxt_i$

找到它的最长前后缀,那这个$nxt_{i+1}$最多就只能匹配到最长前缀那儿了(这个显然趴?不解释不解释$QAQ$

本来$jio$得很显然的样子然后发现自己复习的时候居然没有懂$QAQ$所以我$jio$得我还是再解释下趴$QAQ$

大概就是说,首先显然我们要知道不能匹配之后$nxt_{i+1}$肯定会变小,所以再匹配的时候只要在最前面那一段$1-nxt_i$中匹配就好了

然后对于第$i$位,因为我们已经求出它的$nxt_i$了

那因为我们要往前移了,我们就想移得最少是到哪儿呢?显然是移到$nxt_i$的$nxt$位置上去

对这个问题我们可以先证明不可能在它后面再证明在它前面不是最优的(即充要性×

首先假如$nxt_i$的$nxt$的后面还有一个位置$d$也能满足$d$那儿的字母和$nxt_i$那儿的字母是一样的,然后我们移到了那儿去

既然移到那儿去那就说明$d$及其之前的字母和$i$及其之前的字母都是相等的嘛

然而,因为$d$在$nxt_i$的$nxt$的后面,说明它是不能和$nxt_i$前面那串后缀完全匹配的

然而那个后缀是可以和$i$那段后缀匹配的

所以显然布星

然后如何证明在它前面不是最优?

显然移到$nxt$处是移动最少的辣,那我们只需证明移动到那儿绝对是满足的就可以辣!

因为$nxt_i$前面那串后缀和$nxt_i$的$nxt$那段前缀是匹配的

$nxt_i$前面那串后缀和i前面那串后缀也是匹配的

所以$nxt_i$的$nxt$那段前缀和i那段后缀必然是匹配的

所以是可以满足的

综上,我们证明了我们需要移动到$nxt_i$的$nxt$处并继续匹配$nxt_{nxt_i}+1$和$i+1$

如果相等就又是$nxt[i+1]=nxt[{i}']+1$(此处${i}'$就是最长前缀那儿了$qwq$

不相等继续做,就相当于一个有点递归的过程?能理解趴?不过可以用$while$直接实现掉就是了$qwq$

然后如果一直不相等一直不相等到最后也不能匹配就随便特殊处理下,$over$

然后洛谷上有个板子题可以做下$qwq$

kmp学习笔记kmp学习笔记
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rp(i,x,y) for(register ll i=x;i<=y;++i)

const ll N=1000000+100;
string s1,s2;
vector<ll>as;
ll lth2,nxt[N];

inline ll read()
{
    register char ch=getchar();register ll x=0;register bool y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar();
    if(ch=='-')ch=getchar(),y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return y?x:-x;
}
inline void gtnxt(string str,ll lth)
{
    nxt[0]=-1;
    rp(i,1,lth-1)
    {
        ll nx=nxt[i-1];
        while(str[nx+1]!=str[i] && nx>=0)nx=nxt[nx];
        if(str[nx+1]==str[i])nxt[i]=nx+1;else nxt[i]=-1;
    }
}
inline void kmp()
{
    ll lth1=s1.length(),i=0,j=0;lth2=s2.length();
    gtnxt(s2,lth2);
    while(i<lth1)
    {
//        printf("QAQ i=%lld j=%lld\n",i,j);
        while(s1[i]==s2[j] && j<lth2)++i,++j;
//        printf("!!! : i=%lld j=%lld\n",i,j);
        if(j==lth2){/*printf(",,,QwQ?\n");*/as.push_back(i-lth2+1);j=nxt[j-1]+1;continue;}
        if(j==0)++i;else j=nxt[j-1]+1;
    }
}

int main()
{
    cin>>s1>>s2;kmp();
    ll sz=as.size();rp(i,0,sz-1)printf("%lld\n",as[i]);rp(i,0,lth2-1)printf("%lld ",nxt[i]+1);
    return 0;
}
这儿是咕了很久的代码QAQ

相关文章: