首先来个板子
Luogu P3375
注意字符串要从1开始哦
其实kmp的精髓(自己口胡)就是转移
我们已经知道当前i的next
那么将i右移一位后,我们只要比较当前位和之前的next是否相等即可(next递归下去)
而每次next最多增加1,复杂度就可以保证了
#include<cstdio>
#include<cstring>
const int N=1000000+7;
char a[N],b[N];
int lena,lenb;
int next[N];
void init()
{
next[1]=0;
int j=0;
for(int i=2;i<=lenb;i++)
{
while(j&&b[j+1]!=b[i]) j=next[j];
if(b[j+1]==b[i]) j++;
next[i]=j;
}
}
void match()
{
int j=0;
for(int i=1;i<=lena;i++)
{
while(j&&b[j+1]!=a[i]) j=next[j];
if(b[j+1]==a[i]) j++;
if(j==lenb) printf("%d\n",i-lenb+1);//如果匹配成功了,那么next就会跳到前面继续比较下一个
}
}
int main()
{
scanf("%s %s",a+1,b+1);
lena=strlen(a+1);
lenb=strlen(b+1);
// printf("%d %d\n",lena,lenb);
init();
match();
for(int i=1;i<=lenb;i++) printf("%d ",next[i]);
printf("\n");
return 0;
}
关于next树:
把每个next[i]看成fa[i]
那么我们就可以得到一颗以0为根的树
例题:
1、51nod 1277
那么我们直接从树的底部往上传信息(在本题中直接从n~1枚举即可)然后统计一下答案就可以了
2、bzoj3670: [Noi2014]动物园
最暴力的方法就是从next[i]一直next下去
直到为0,然后统计ans
然而我们可以统计每一个点在next树上的深度dep
那么我们只要找出第一个j,其中2*j<=i,它的dep就是num[i]了
考虑我们怎么求出每个i的第一个j
发现这个东西类似next数组,是可以转移的
将i右移一位后,它指向的j也最多只能+1
所以我们只用扫一遍就可以了
核心代码:(next,dep已经处理好了)
long long ans=1;
j=0;
for(int i=2;i<=n;i++)
{
while(j&&a[j+1]!=a[i]) j=next[j];
if(a[j+1]==a[i]) j++;
while(j&&(j<<1)>i) j=next[j];
ans=ans*(dep[j]+1)%mod;
}