LA 4670 所有出现最多次的模式串 AC自动机

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2671

题意:

给定n个模式串

第n+1行给定文本串

问:

 在文本串出现最多次的模式串  出现的次数和所有出现最多次的模式串(按字典序输出)

 

思路:

AC自动机模版题

#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;

#define N 1000010
#define maxnode 250001
#define sigma_size 26
struct node{
	char ch[80];
}ans[200];
int top;
struct Trie{
	int ch[maxnode][sigma_size];
	int val[maxnode];
	int last[maxnode];
	int f[maxnode];
	int num[maxnode];
	int pre[maxnode];
	int len[maxnode];
	int Char[maxnode];
	int sz;
	void init(){
		sz=1;
		memset(ch,0,sizeof(ch));
		memset(val, 0, sizeof(val));  
		memset(f,0,sizeof(f));
		memset(last,0,sizeof(last));    //记录该节点前一个节点是谁
		memset(len, 0, sizeof(len));
	}
	int idx(char c){ return c-'a'; }
	void print(int j, char *s){
		s[len[j]] = 0;
		while(j){
			s[len[j]-1] = Char[j];
			j = pre[j];
		}
	}
	int insert(char *s){
		int u = 0;
		for(int i = 0; s[i] ;i++){
			int c = idx(s[i]);
			if(!ch[u][c])
				ch[u][c] = sz++;
			pre[ch[u][c]] = u;
			Char[ch[u][c]] = s[i];
			len[ch[u][c]] = len[u]+1;
			u = ch[u][c];
		}
		val[u] ++;
		num[u] = 0;
		return u;
	}
	void getFail(){
		queue<int> q;
		for(int i = 0; i<sigma_size; i++)
			if(ch[0][i]) q.push(ch[0][i]);  

		while(!q.empty()){
			int r = q.front(); q.pop();  
			for(int c = 0; c<sigma_size; c++){
				int u = ch[r][c];
				if(!u)continue;
				q.push(u);
				int v = f[r];
				while(v && ch[v][c] == 0) v = f[v]; //沿失配边走上去 如果失配后有节点 且 其子节点c存在则结束循环     
				f[u] = ch[v][c];
				last[u] = val[f[u]] ? f[u] : last[f[u]];
			}
		}
	}
	void find(char *T){
		int j = 0;
		for(int i = 0; T[i] ; i++){
			int c = idx(T[i]);
			while(j && ch[j][c]==0) j = f[j];
			j = ch[j][c];

			int temp = j;
			while(temp){ //沿失配边走 || 若沿失配边走时一定要节点为单词结尾则改成while(temp && val[temp])
				if(val[temp])num[temp]++;
				temp = f[temp];
			}
		}
	}
	int bestnum(){
		queue<int>q;
		int best = 0;
		for(int i = 0; i < sigma_size; i++)
		{
			if(ch[0][i])q.push(ch[0][i]);
			if(val[ch[0][i]])best = max(best, num[ch[0][i]]);
		}
		while(!q.empty())
		{
			int r = q.front(); q.pop();
			for(int c = 0; c < sigma_size; c++){
				int u = ch[r][c];
				if(!u)continue;
				q.push(u);
				if(val[u])best = max(best, num[u]);
			}
		}
		return best;
	}
	void match(int best){
		queue<int>q;
		for(int i = 0; i < sigma_size; i++)
		{
			if(ch[0][i])q.push(ch[0][i]);
			if(val[ch[0][i]] && num[ch[0][i]]==best)print(ch[0][i], ans[top++].ch);
		}
		while(!q.empty())
		{
			int r = q.front(); q.pop();
			for(int c = 0; c < sigma_size; c++){
				int u = ch[r][c];
				if(!u)continue;
				q.push(u);
				if(val[u] && num[u] == best)print(u, ans[top++].ch);
			}
		}
	}
};
Trie ac;
char s[1000006];
bool cmp(node a,node b){return strcmp(a.ch, b.ch)<0;}
int main(){
	int n, i;
	while(scanf("%d",&n), n){
		ac.init();
		for(i = 0; i < n; i++)scanf("%s", s), ac.insert(s);
		ac.getFail();
		scanf("%s", s);
		ac.find(s);
		int best = ac.bestnum();
		printf("%d\n", best);
		top=0;
		ac.match(best);
		sort(ans, ans+top, cmp);
		for(i = 0; i < top; i++)printf("%s\n", ans[i].ch);
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值