AC自动机学习

news/2024/10/12 13:09:21

左程云讲解102

加了fail指针的前缀树

通过在前缀树上构建fail指针,如下图,abcda,abcdb,bcdc

如果我要查询的是abcdcdc

先顺着1234号结点向下,abcdc,遇到最后的c时当前串上找不到了,通过fail跳到bcdc串上,因为abcd后缀和bcdc前缀重合,这么跳能减少重新匹配的成本

相当于对于要查询的串,我先从0位置开始,找abcbc找不到,那么继续从1为止开始,bcdc找得到,那么10结点答案+1,表示bcdc词频+1

保留所有匹配成功的可能性

优化

优化1

问题:fail在构建的时候,遇到匹配不到的会往上跳再往下跳

解决方案:插入的次数较多,会出现重复跳同一条路径,那么在构建trie时,直接在表中将跳到的点构建好,实现使用功能时一次跳转到位,相当于把trie变成直通表,以后只要跳一次

优化2

问题:查询时候,每次到一个点都需要把往上的所有fail词频+1,但是如果反复经过一个词频,就需要反复走同一条路径

所以如下图所示,先只处理结点

完毕后根据fail建立反图,那么某个节点的贡献就是子树的贡献和

CODE

// #pragma GCC optimize(2)
// P5357 【模板】AC 自动机 https://www.luogu.com.cn/problem/P5357
#include <bits/stdc++.h>
using namespace std;#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define rep(i, j, k) for (int i = (j); i < (k); i++)
#define all(x) x.begin(), x.end()
#define pii pair<int, int>/* AC自动机 */
const int N = 2e5 + 10; // 目标字符串的数量,有存储终止节点编号的需求
const int S = 2e5 + 10; // 所有目标串的总字符数量
int ed[N];              // 每个目标串的结点编号 end
int tree[S][26];
int fail[S];
int cnt = 0; // 指针编号/* 具体题目,本题为收集词频 */
int times[N];/* 建反图,链式前向星 */
int edge = 0;
int head[S];
int nxt[S];
int to[S];
void addEdge(int u, int v) {nxt[++edge] = head[u];head[u] = edge;to[edge] = v;
}inline int get(char ch) {return ch - 'a';
}void insert(int i, string &s) {int p = 0;for (char ch : s) {int u = get(ch);if (!tree[p][u]) tree[p][u] = ++cnt;p = tree[p][u];}ed[i] = p;
}void setFail() {queue<int> q;                  // BFSfor (int i = 0; i < 26; i++) { // 0结点的子入队if (tree[0][i]) q.push(tree[0][i]);}while (q.size()) {int u = q.front();q.pop();for (int i = 0; i < 26; i++) {if (!tree[u][i]) { // 如果当前有节点,那么指向fail指针的对应子节点tree[u][i] = tree[fail[u]][i]; // 直通表的修改} else {/* 优化1部分 */// 有孩子,那么当前点的孩子(假定是b)的fail,需要指向当前点的fail指针的b孩子// 且因为是BFS的遍历,当前节点的fail一定是当前层或上层,是已经构建完毕的,不用担心有些fail的子节点没建好fail[tree[u][i]] = tree[fail[u]][i]; // 设置孩子的fail指针为自己fail指针的孩子q.push(tree[u][i]); // 正常步骤,将孩子加到队列中去}}}
}// 汇总词频
void dfs(int u) {for (int e = head[u]; e != 0; e = nxt[e]) {dfs(to[e]);times[u] += times[to[e]];}
}int main() {IOS;fill_n(times, S, 0);int n;cin >> n;rep(i, 1, n + 1) {string s;cin >> s;insert(i, s);}setFail();string t;cin >> t;for (int i = 0, u = 0; i < t.size(); i++) {int j = get(t[i]);u = tree[u][j];times[u]++;}for (int i = 1; i <= cnt; i++) { // 注意,是有多少tree的编号就add多少次addEdge(fail[i], i);}dfs(0);for (int i = 1; i <= n; i++) {cout << times[ed[i]] << endl;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/70625.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

老人摔倒智能检测报警系统

老人摔倒智能检测报警系统利用监控摄像头和智能算法,老人摔倒智能检测报警系统实时监测老人的活动状态,老人摔倒智能检测报警系统通过现场监控摄像头感知老人是否发生摔倒,并通过智能算法进行分析和判断,一旦发现摔倒事件,老人摔倒智能检测报警系统立即触发报警装置发送求…

加油站ai视觉分析预警系统

加油站AI视觉分析预警系统利用摄像头和人工智能技术,加油站ai视觉分析预警系统实时监测人员的行为。加油站ai视觉分析预警系统通过图像识别和行为分析,识别出打电话抽烟、烟火行为、静电释放时间是否合规以及人员工服等不符合规定的行为,并发出预警信号以提醒相关人员。加油…

智慧课堂学生行为检测评估系统

智慧课堂学生行为检测评估系统利用摄像头和人工智能技术,智慧课堂学生行为检测评估系统实时监测学生的上课行为,智慧课堂学生行为检测评估系统通过图像识别和行为分析,评估学生的表情、是否交头接耳行为、课堂参与度以及互动质量,并提供相应的反馈和建议。智慧课堂学生行为…

微信公众号客服系统-接收对话框文本图片视频消息

如果您的需求是客户在公主号对话框里发送消息 不管是文本、图片、视频,都接收到自己服务端。 那么可以尝试我们的在线客服系统 唯一客服系统 gofly.v1kf.com 我们系统已经对接了微信公主号的API,可以将公众号消息保存在自己服务端 十年开发经验程序员,离职全心创业中,历时三…

[题目记录]一本通高手训练-数列

题意 定义 n-数列 为满足以下条件的数列 \({a_i}\) :数列长度不小于 \(3\) , 且每个元素为 \(1\) 到 \(n\) 的整数 . 对于任意 \(k \ge 3\) , 有 $ (a_k-a_{k-2})(a_{k-1}-a_{k-2})<0$ .给出 \(n\) , 求 n-数列 的个数 , 对 \(10^9+7\) 取模 . \(n\le 10^{500000}\) 时空限制…

AOT漫谈专题(第二篇): 如何对C# AOT轻量级APM监控

一:背景 1. 讲故事 上一篇我们聊到了如何调试.NET Native AOT 程序,这是研究一个未知领域知识的入口,这篇我们再来看下如何对 Native AOT 程序进行轻量级的APM监控,当然这里的轻量级更多的是对 AOT 中的coreclr内容的挖掘。 二:如何轻量级APM监控 1. 一个简单的例子 用一个…

Windows平台软件打包工具(inno setup)的使用

目录Windows平台软件打包工具(inno setup)的使用inno setup中文版下载地址inno setup介绍软件特色Inno setup 打包教程 Windows平台软件打包工具(inno setup)的使用 inno setup中文版下载地址 正版下载:https://jrsoftware.org/isdl.php 中文版下载:链接: https://pan.bai…

Leetcode 1192. 查找集群内的关键连接

1.题目基本信息 1.1.题目描述 力扣数据中心有 n 台服务器,分别按从 0 到 n-1 的方式进行了编号。它们之间以 服务器到服务器 的形式相互连接组成了一个内部集群,连接是无向的。用 connections 表示集群网络,connections[i] = [a, b] 表示服务器 a 和 b 之间形成连接。任何服…