洛谷P3796 【模板】AC自动机(加强版)
? 解题记录 ? ? 洛谷 ? ? AC自动机 ?    2017-11-18 17:07:44    342    0    0

题目描述

NN个由小写字母组成的模式串以及一个文本串TT。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串TT中出现的次数最多。

输入输出格式

输入格式:

 

输入含多组数据。

每组数据的第一行为一个正整数NN,表示共有NN个模式串,1 \leq N \leq 1501N150

接下去NN行,每行一个长度小于等于7070的模式串。下一行是一个长度小于等于10^6106的文本串TT

输入结束标志为N=0N=0

 

输出格式:

 

对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

 

输入输出样例

输入样例#1: 复制
2
aba
bab
ababababac
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
0
输出样例#1: 复制
4
aba
2
alpha
haha

模板题一道,就是输出很蛋疼。另外trie树写指针版真的快得多(1~2s),但是还是用数组比较好写。

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1e6 + 5;
int mx = 0;

namespace Aho_Corasick {
	int trie[maxn][26], fail[maxn], cnt, sum[maxn], fixed[maxn];
	int init() {
		cnt = 0, mx = 0;
		memset(trie, 0, sizeof(trie));
		memset(fail, 0, sizeof(fail));
		memset(sum, 0, sizeof(sum));
		memset(fixed, 0, sizeof(fixed));
		fail[0] = -1;
	}
	int insert(char * s) {
		int len = strlen(s);
		int now = 0, id;
		for(register int i = 0; i < len; ++i) {
			id = s[i] - 'a';
			if(trie[now][id]) now = trie[now][id];
			else now = trie[now][id] = ++cnt;
		}
		++sum[now];
	}
	void create() {
		queue<int > q;
		q.push(0);
		while(!q.empty()) {
			int u = q.front();
			q.pop();
			for(register int i = 0; i < 26; ++i) {
				if(!trie[u][i]) continue; 
				int p = fail[u];
				while(~p && !trie[p][i])
					p = fail[p];
				if(p != -1) fail[trie[u][i]] = trie[p][i];
				q.push(trie[u][i]);
			}
		}
	}
	void work(char * s) {
		int len = strlen(s), now = 0;
		for(register int i = 0; i < len; ++i) {
			int id = s[i] - 'a';
			while(now && !trie[now][id])
				now = fail[now];
			if(now != -1) now = trie[now][id];
			int p = now;
			while(p) {
				++fixed[p];
				if(sum[p]) mx = max(mx, fixed[p]);
				p = fail[p];
			}
		}
	}
	void judge(char * s) {
		int len = strlen(s), now = 0;
		for(register int i = 0; i < len; ++i) {
			if(!trie[now][s[i] - 'a']) return;
			now = trie[now][s[i] - 'a'];
		}
		if(fixed[now] != mx) return ;
		for(register int i = 1; i <= sum[now]; ++i)
			printf("%s\n", s);
	}
}

#define AC Aho_Corasick
int n, m;
char s[205][205], art[maxn];
char res[205];
int main() {
	while(1) {
		scanf("%d", &n);
		if(n == 0) break;
		AC::init();
		for(register int i = 1; i <= n; ++i) {
			scanf("%s", s[i]);
			AC::insert(s[i]);
		}
		AC::create();
		scanf("%s", art);
		AC::work(art);
		printf("%d\n", mx);
		for(register int i = 1; i <= n; ++i)
			AC::judge(s[i]);
	}
	return 0;
}


上一篇: P3391 【模板】文艺平衡树(Splay)

下一篇: BZOJ2565: 最长双回文串

342 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航