簡介
序列自動機是一個可以快速判斷字符串\(t\)是否是字符串\(s\)的子串的一個算法。
構造
對\(s\)構造序列自動機,使用\(Nxt_{i,j}\)代表從第\(i\)個位置開始,字符\(j\)出現的第一個位置。我們倒着遍歷更新即可。
int nxt[N][27];
void init(char *s){
int l=strlen(s);
for(int i=0;i<26;i++) nxt[l][i]=INF;
for(int i=l-1;i>=0;i--){
for(int j=0;j<26;j++){
nxt[i][j]=nxt[i+1][j];
}
nxt[i][s[i]-'a']=i;
}
}
查詢
設置初始指針\(p\)為-1,每次讓\(p\)跳到\(Nxt_{p+1,j}\)上面,\(j\)為當前查詢的字符,如果\(p\)為\(INF\),則說明找不到下一個字符,即\(t\)不是\(s\)的子串。
bool find(char *t){
int pos=-1;
int l=strlen(t);
for(int i=0;i<l;i++){
pos=nxt[pos+1][t[i]-'a'];
if(pos==INF) return 0;
}
return 1;
}
模板
struct sub_AM{
int nxt[N][27];
void init(char *s){
int l=strlen(s);
for(int i=0;i<26;i++) nxt[l][i]=INF;
for(int i=l-1;i>=0;i--){
for(int j=0;j<26;j++){
nxt[i][j]=nxt[i+1][j];
}
nxt[i][s[i]-'a']=i;
}
}
bool find(char *t){
int pos=-1;
int l=strlen(t);
for(int i=0;i<l;i++){
pos=nxt[pos+1][t[i]-'a'];
if(pos==INF) return 0;
}
return 1;
}
}solve;
Problems
計蒜客 Subsquenece
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
const int INF = 0x3f3f3f3f;
char s[N];
char t[N];
struct sub_AM{
int nxt[N][27];
void init(char *s){
int l=strlen(s);
for(int i=0;i<26;i++) nxt[l][i]=INF;
for(int i=l-1;i>=0;i--){
for(int j=0;j<26;j++){
nxt[i][j]=nxt[i+1][j];
}
nxt[i][s[i]-'a']=i;
}
}
bool find(char *t){
int pos=-1;
int l=strlen(t);
for(int i=0;i<l;i++){
pos=nxt[pos+1][t[i]-'a'];
if(pos==INF) return 0;
}
return 1;
}
}solve;
int main(){
scanf("%s",s);
solve.init(s);
int q;
scanf("%d",&q);
while(q--){
scanf("%s",t);
if(solve.find(t)){
puts("YES");
}
else puts("NO");
}
return 0;
}