各个测试点1s
exkmp~~~ctrl_c+ctrl_v
假如有匹配串A长度为N,模式串B长度为M,那么扩展KMP算法可以在O(N+M)的时间内算出对于A的每一个位置,与B的最长匹配长度是多少(即与B串前缀重合的最长长度),算法如下:
PART_1 初始化next数组
设next[i]表示B串的i位置开始的字符串与B串的前缀的最长重合长度(注意这里与KMP中的next是不一样的)。明显地,next[1]=M(我的字符串的下标习惯从1开始),next[2]也可以用一个简单的for循环求出,pos初始化为2;当i∈[3,M]时,我首先认为关于1~i-1的信息已全部求出,我们记录一个pos,它的意义是当前已计算出的next数组中,j+next[j]-1能达到的最右端所对应的i,这个不太好理解,可以参考manacher算法的思想戳这(其实manacher和扩展kmp是很像的),令rp=pos+next[pos]-1
(1)当i+next[i-pos+1]<rp时,易得next[i]=next[i-pos+1]
(2)当i+next[i-pos+1]>=rp时,rp后的元素,即b[rp+j],可能会和b[rp-i+1+j]相等,这时进行暴力扩展,如果扩展发生,则更新pos为i,next[i]直接在扩展中求出。
注意:有时rp可能小于i,这时可以加一特判,直接进行暴力求
PART_2 匹配
令ans[i]表示a串中以a[i]为开头的后缀和b串的最长匹配长度,设pos表示a串中对于所有的i,i+ans[i]-1能达到的最远位置对应的i,rp就是pos+ans[pos]-1,next[1]暴力求出,pos初始化为1;当i∈[2,N]时:
(1)若i+next[i-pos+1]-1<rp,则ans[i]=next[i-pos+1]
(2)若i+next[i-pos+1]-1>=rp,则进行暴力扩展,同时更新pos,ans在扩展时求出
注意:如果rp<i,那么加一特判,直接暴力扫描
这个题就明了了~~~
1 #include <algorithm>
2 #include <cstring>
3 #include <cstdio>
4
5 using namespace std;
6
7 const int N(200000+5);
8 int n,m,k,lb,la;
9 int p[N],ans[N];
10 char a[N],b[N];
11
12 inline void Get_next()
13 {
14 for(int i=2,j=0;i<=lb;p[i++]=j)
15 {
16 for(;b[i]!=b[j+1]&&j>0;) j=p[j];
17 if(b[i]==b[j+1]) j++;
18 }
19 }
20 inline void kmp()
21 {
22 for(int i=1,j=0;i<=la;i++)
23 {
24 for(;a[i]!=b[j+1]&&j>0;) j=p[j];
25 if(a[i]==b[j+1]) j++;
26 ans[j]++;
27 }
28 }
29
30 int main()
31 {
32 scanf("%d%d%d%s%s",&n,&m,&k,a+1,b+1);
33 la=strlen(a+1); lb=strlen(b+1);
34 Get_next(); kmp();
35 for(int i=lb;i>0;i--) ans[p[i]]+=ans[i];
36 for(int i=0;i<lb;i++) ans[i]-=ans[i+1];
37 for(int pos;k--;)
38 {
39 scanf("%d",&pos);
40 printf("%d\n",ans[pos]);
41 }
42 return 0;
43 }