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;
}
posted @ 2021-10-10 23:53  尹昱钦  阅读(49)  评论(0编辑  收藏  举报