AC自动机 & 洛谷 P3808 【模板】AC自动机(简单版)& P3796 【模板】AC自动机(加强版)
传送门(简单版)
传送门(加强版)
AC自动机
推荐阅读:洛谷日报
讲的真的很好。
我没法再说的更好了。
甚至我的板子都是照着他的敲的。
加强版
说是加强版,实际上只需更改一下num数组表示的含义:从当前点有几个模式串结尾,改成以当前点结尾的模式串的编号。
在查询过程中也不需要清空num标记。
注意数组清空。
AC代码(简单版)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1e6+5;
int tr[maxn][30],cnt,num[maxn],fail[maxn];
int n;
string s;
void insert(string s){
int now=0,len=s.length();
for(int i=0;i<len;i++){
int k=s[i]-'a';
if(!tr[now][k]) tr[now][k]=++cnt;
now=tr[now][k];
}
num[now]++;
}
void build(){
queue<int> q;
for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
while(!q.empty()){
int now=q.front();q.pop();
for(int i=0;i<26;i++){
if(tr[now][i]){
fail[tr[now][i]]=tr[fail[now]][i];
q.push(tr[now][i]);
}else{
tr[now][i]=tr[fail[now]][i];
}
}
}
}
int query(string s){
int now=0,res=0,len=s.length();
for(int i=0;i<len;i++){
now=tr[now][s[i]-'a'];
for(int j=now;j&&~num[j];j=fail[j]) res+=num[j],num[j]=-1;
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>s,insert(s);
cin>>s;
build();
cout<<query(s)<<endl;
return 0;
}
AC代码(加强版)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=2e4+5;
int tr[maxn][30],cnt,num[maxn],fail[maxn];
int n,ans_cnt,ans[maxn],anss[maxn];
string s[205];
void insert(string s,int id){
int now=0,len=s.length();
for(int i=0;i<len;i++){
int k=s[i]-'a';
if(!tr[now][k]) tr[now][k]=++cnt;
now=tr[now][k];
}
num[now]=id;
}
void build(){
queue<int> q;
memset(fail,0,sizeof(fail));
for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
while(!q.empty()){
int now=q.front();q.pop();
for(int i=0;i<26;i++){
if(tr[now][i]){
fail[tr[now][i]]=tr[fail[now]][i];
q.push(tr[now][i]);
}else{
tr[now][i]=tr[fail[now]][i];
}
}
}
}
int query(string s){
memset(ans,0,sizeof(ans));
int now=0,res=0,len=s.length();
for(int i=0;i<len;i++){
now=tr[now][s[i]-'a'];
for(int j=now;j;j=fail[j]) ans[num[j]]++;
}
for(int i=1;i<=n;i++){
if(res<ans[i]){
res=ans[i];
ans_cnt=0;
}
if(res==ans[i]) anss[++ans_cnt]=i;
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin>>n;
while(n){
memset(tr,0,sizeof(tr));
memset(num,0,sizeof(num));
cnt=ans_cnt=0;
for(int i=1;i<=n;i++) cin>>s[i],insert(s[i],i);
cin>>s[n+1];
build();
cout<<query(s[n+1])<<endl;
for(int i=1;i<=ans_cnt;i++) cout<<s[anss[i]]<<endl;
cin>>n;
}
return 0;
}