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 @   YHXo  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示