Luogu3808&3796&5357 - AC自动机 -

AC自动机:多模式串匹配,能做到线性复杂度

原理大概就是建出trie树,用fail[x]=p表示x结点所表示的字符串的后缀与p结点所表示的字符串前缀相同
匹配的时候就每次跳fail就行了,利用trie图进行优化
三题均为模板题,在匹配成功时统计答案略有不同

3808

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e6+5;

int n;
char t[maxn], s[maxn];

struct AC{
	int lst[maxn];
	int tr[maxn][27],cnt;
	int val[maxn];	// 多少个以 i 结点结尾的单词 
	int fail[maxn];
	
	AC(){cnt=0;memset(val,0,sizeof val);}
	
	void insert(char *s){
		int p=0;
		int ns = strlen(s + 1);
		for(int i=1;i<=ns;i++){
			int k = s[i] - 'a';
			if(!tr[p][k])tr[p][k] = ++ cnt;
			p = tr[p][k];
		}
		++ val[p];
	}
	
	void build(){
		queue<int>Q;
		Q.push(0);
		while(!Q.empty()){
			int u = Q.front();Q.pop();
			for(int i=0;i<26;i++)
				if(tr[u][i]){
					fail[tr[u][i]] = u ? tr[fail[u]][i] : 0;
					if(val[fail[tr[u][i]]])lst[tr[u][i]] = fail[tr[u][i]];
					else lst[tr[u][i]] = lst[fail[tr[u][i]]];
					
					Q.push(tr[u][i]);
				}else tr[u][i] = tr[fail[u]][i];
		}
	}
	
	void query(char *t){
		int p=0, res=0;
		int nt = strlen(t + 1);
		for(int i=1;i<=nt;i++){
			p = tr[p][t[i] - 'a'];
			if(val[p])res += val[p], val[p] = 0;
			int v = lst[p];
			while(v){	// 沿失配边跳,加上abc bc c这种的匹配 
				if(val[v])res += val[v], val[v] = 0;
				v = lst[v];
			}
		}
		printf("%d\n",res);
	}
}ac;

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s +1);
		ac.insert(s);
	}
	
	ac.build();
	scanf("%s", t+ 1);
	ac.query(t);

	return 0;
}

3796

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <map> 
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e6+5;

int n;
char t[maxn], s[152][maxn];

struct AC{
	int lst[maxn];
	int tr[maxn][27],cnt;
	int val[maxn];	// 多少个以 i 结点结尾的单词 
	int fail[maxn];
	map<int,int>end;	// 无重复的串,end[p]=id trie上p号点到根代表第 id 个字符串 
	map<int,int>cou;
	
	void clear(){
		cnt=0;memset(lst,0,sizeof lst);memset(fail,0,sizeof fail);
		end.clear();cou.clear();memset(tr,0,sizeof val);memset(val,0,sizeof val);
	}
	
	void insert(char *s,int id){
		int p=0;
		int ns = strlen(s + 1);
		for(int i=1;i<=ns;i++){
			int k = s[i] - 'a';
			if(!tr[p][k])tr[p][k] = ++ cnt;
			p = tr[p][k];
		}
		++ val[p];
//		printf("map : %d -> %d\n",p,id); 
		end[p] = id;
	}
	
	void build(){
		queue<int>Q;
		Q.push(0);
		while(!Q.empty()){
			int u = Q.front();Q.pop();
			for(int i=0;i<26;i++)
				if(tr[u][i]){
					fail[tr[u][i]] = u ? tr[fail[u]][i] : 0;
					if(val[fail[tr[u][i]]])lst[tr[u][i]] = fail[tr[u][i]];
					else lst[tr[u][i]] = lst[fail[tr[u][i]]];
					
					Q.push(tr[u][i]);
				}else tr[u][i] = tr[fail[u]][i];
		}
	}
	
	void query(char *t){
		int p=0, res=0;
		int nt = strlen(t + 1);
		for(int i=1;i<=nt;i++){
			p = tr[p][t[i] - 'a'];
			if(val[p]){
				res += val[p];
				++ cou[p];
			}
			int v = lst[p];
			while(v){	// 沿失配边跳,加上abc bc c这种的匹配 
				if(val[v]){
					res += val[v];
					++ cou[v];
				}
				v = lst[v];
			}
		}
		int mx = -1e9;
		vector<int> ansid;
		for(auto it : cou){
			if(mx < it.second){
				ansid.clear();
				mx = it.second, ansid.push_back(it.first);
			}else if(mx == it.second)ansid.push_back(it.first);
//			printf("%d %d\n",it.first,it.second);
		}
		printf("%d\n",mx);
		for(int u : ansid)
			printf("%s\n",s[end[u]] + 1);
//		printf("%d\n",res);
	}
}ac;

signed main(){
	while(scanf("%d",&n), n){
		ac.clear();
		for(int i=1;i<=n;i++){
			scanf("%s",s[i] +1);
			ac.insert(s[i], i);
		}
		
		ac.build();
		scanf("%s", t+ 1);
		ac.query(t);
	}

	return 0;
}

5357

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <map> 
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e6+5, maxm = 2e6+5;

int n;
char t[maxm], s[maxn];

struct AC{
	int lst[maxn];
	int tr[maxn][27],cnt;
	int val[maxn];	// 多少个以 i 结点结尾的单词 
	int fail[maxn];
	int cou[maxn];
	int idtop[maxn];	// id to p
	
	void insert(char *s,int id){
		int p=0;
		int ns = strlen(s + 1);
		for(int i=1;i<=ns;i++){
			int k = s[i] - 'a';
			if(!tr[p][k])tr[p][k] = ++ cnt;
			p = tr[p][k];
		}
		++ val[p];
		idtop[id] = p;
	}
	
	void build(){
		queue<int>Q;
		Q.push(0);
		while(!Q.empty()){
			int u = Q.front();Q.pop();
			for(int i=0;i<26;i++)
				if(tr[u][i]){
					fail[tr[u][i]] = u ? tr[fail[u]][i] : 0;
					if(val[fail[tr[u][i]]])lst[tr[u][i]] = fail[tr[u][i]];
					else lst[tr[u][i]] = lst[fail[tr[u][i]]];
					
					Q.push(tr[u][i]);
				}else tr[u][i] = tr[fail[u]][i];
		}
	}
	
	void query(char *t){
		int p=0, res=0;
		int nt = strlen(t + 1);
		for(int i=1;i<=nt;i++){
			p = tr[p][t[i] - 'a'];
			if(val[p]){
				res += val[p];
				++ cou[p];
			}
			int v = lst[p];
			while(v){	// 沿失配边跳,加上abc bc c这种的匹配 
				if(val[v]){
					res += val[v];
					++ cou[v];
				}
				v = lst[v];
			}
		}
		for(int i=1;i<=n;i++){
			printf("%d\n",cou[idtop[i]]);
		}
	}
}ac;

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s +1);
		ac.insert(s, i);
	}
	
	ac.build();
	scanf("%s", t+ 1);
	ac.query(t);

	return 0;
}
posted @ 2022-11-16 22:07  SkyRainWind  阅读(12)  评论(0编辑  收藏  举报