cf-edu134-E,KMP的代替物?(速度超快)


Prefix Function Queries

题目传送门

题意

有一个长度为 $n(1 \leq n \leq 10^6)$ 的字符串 $s$ ,有 $q(1 \leq q \leq 10^5)$ 次询问。

每次询问给出一个非空字符串 $t(1 \leq |t| \leq 10)$ ,如果把 $t$ 拼接到 $s$ 的后面,求长度为 $n+1,n+2, \dots ,n+|t|$ 的前缀的最长相同前缀后缀。(即求 $KMP$ 中的 $pmt$ 数组的 $pmt[n+1],pmt[n+2], \dots ,pmt[n+|t|]$ )。

思路

我刚开始感觉这就是个 $KMP$ 的裸题,但是在我交了上去并发现 $T$ 了的时候,感觉又不像是 $KMP$ 。

然后,在今天题解出来之后,我看了一下,发现了一个叫前缀函数自动机的东西,这个东西和 $AC自动机$ 极其类似,都有一个叫失配指针的东西,然后这东西又有点像 $Trie 树$ ,有着相似的转移。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<bits/stdc++.h>
#define Inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef pair<int,int> P;
const int MAXX=1000050;

int n,q;
char s[MAXX];
int fail[MAXX],ch[MAXX][26];

inline void solve(){
scanf("%s%d",s+1,&q);
n=strlen(s+1);

ch[0][s[1]-'a']=1;
for(int i=2;i<=n;++i){
for(int j=0;j<26;++j){
if(s[i]-'a'==j){
ch[i-1][j]=i;
fail[i]=ch[fail[i-1]][j];
}
else
ch[i-1][j]=ch[fail[i-1]][j];
}
}

while(q--){
getchar();scanf("%s",s+n+1);
int nn=strlen(s+n+1)+n;
for(int i=n+1;i<=nn;++i){
for(int j=0;j<26;++j){
if(s[i]-'a'==j){
ch[i-1][j]=i;
fail[i]=ch[fail[i-1]][j];
}
else
ch[i-1][j]=ch[fail[i-1]][j];
}
}

for(int i=n+1;i<=nn;++i)
printf("%d%c",fail[i]," \n"[i==nn]);
}

}

signed main(){
// LL t;scanf("%lld",&t);
// while(t--)
solve();

return 0;
}

总结

感觉这个东西在只需要求 $pmt$ 数组的时候,可以作为 $KMP$ 的替代品。


文章作者: Shaun
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Shaun !
评论
  目录