P3796 【模板】AC 自动机(加强版)

P3796
差不多还是AC自动机的模板,不过求解得问题不同,这里trie树节点end维护以该点结尾的单词的编号,这样方便我们统计每个模式串出现的次数,最后找到次数最多的模式串即可。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct trie {
	int fail;
	int vis[30];
	int end;
}ac[N];
#define ac(x, i) ac[x].vis[i]
int n, tot = 0;
struct node {
	int num, pos;
}ans[N];
bool operator < (node a, node b) {
	return (a.num == b.num) ? a.pos < b.pos : a.num > b.num;
}
string s[N];
void build(string s, int Num) {
	int len = s.length();
	int p = 0;
	for (int i = 0; i < len; i ++) {
		if (ac(p, s[i] - 'a') == 0)
			ac(p, s[i] - 'a') = ++ tot;
		p = ac(p, s[i] - 'a');
	}
	ac[p].end = Num;//标记结尾处单词的编号 
}
void getfail() {
	queue<int> q;
	for (int i = 0; i < 26; i ++) {
		if (ac(0, i) != 0) {
			ac[ac(0, i)].fail = 0;
			q.push(ac(0, i));
		}
	}
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = 0; i < 26; i ++) {
			if (ac(u, i) != 0) {
				ac[ac(u, i)].fail = ac(ac[u].fail, i);
				q.push(ac(u, i));
			}
			else ac(u, i) = ac(ac[u].fail, i);
		}
	}
}
void query(string s) {
	int len = s.length();
	int p = 0;
	for (int i = 0; i < len; i ++) {
		p = ac(p, s[i] - 'a');
		for (int k = p; k; k = ac[k].fail) 
			ans[ac[k].end].num ++;
	}
}
int main() {
	while(1) {
		scanf("%d", &n);
		if (n == 0) break;
		memset((void *) &ac, 0x00, sizeof ac);
		tot = 0;
		for (int i = 1; i <= n; i ++) {
			cin >> s[i];
			ans[i].num = 0;
			ans[i].pos = i;
			build(s[i], i);
		}
		ac[0].fail = 0;
		getfail();
		cin >> s[0];//文本串
		query(s[0]); 
		sort(ans + 1, ans + n + 1);
		cout << ans[1].num << '\n';
		cout << s[ans[1].pos] << '\n';
		for (int i = 2; i <= n; i ++) {
			if (ans[i].num == ans[i - 1].num) 
				cout << s[ans[i].pos] << '\n';
			else break;
		}
	}
	return 0;
}

image

posted @ 2022-10-11 21:10  YHXo  阅读(30)  评论(0)    收藏  举报