首页 > 其他分享 >AC自动机学习

AC自动机学习

时间:2024-10-12 13:00:24浏览次数:1  
标签:AC int tree 学习 ++ 词频 fail 自动机 指针

左程云讲解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;                  // BFS
    for (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;
}

标签:AC,int,tree,学习,++,词频,fail,自动机,指针
From: https://www.cnblogs.com/lulaalu/p/18460305

相关文章

  • HEU KMS Activator v42.3.0
    不多做介绍了,懂得自然懂!123网盘:https://www.123pan.com/s/DMeA-sIuxA.html......
  • 985研一学习日记 - 2024.10.11
    偶尔一碗热鸡汤:一个人内耗,说明他活在过去;一个人焦虑,说明他活在未来。只有当一个人平静时,他才活在现在。日常1、6:00起床√2、健身1h今天练了肩部以及背,然后跑步半小时3、LeetCode刷了2题括号生成:回溯、中仍然使用递归+回溯的方法,递归遍历字符串,每遇到一个)就在其......
  • 网络安全学习路线图(2024版详解)
    近期,大家在网上对于网络安全讨论比较多,想要学习的人也不少,但是需要学习哪些内容,按照什么顺序去学习呢?其实我们已经出国多版本的网络安全学习路线图,一直以来效果也比较不错,本次我们针对市场需求,整理了一套系统的网络安全学习路线图,供大家学习参考。希望大家按照路线图进行系......
  • Mac 最大连接数和端口的相关参数
    1.最大连接数限制最大连接数限制就是系统所能打开的最大文件数(文件描述符)的限制,分全局和进程两种:1.1.全局$sysctlkern.maxfileskern.maxfiles:49152##系统默认的最大连接数限制是49152$sudosysctl-wkern.maxfiles=1048600###设置系统最大连接数从49152到10......
  • RBAC管理系统审计记录
    RBAC管理系统审计记录环境搭建环境依赖Windowsidea2022jdk8RBAC源码phpstudy的mysql5.6.7简易搭建流程(Windows下)直接使用idea打开项目,然后选中右上角的项目构建项目中有几处需要修改:○1、要开启phpstudy的mysql,然后创建rbac数据库,并将源码中的rbac.sql数据导入......
  • winform 同时打开多个窗体,获取当前操作(Active)的窗体.
    最近工作项目中使用winform开发时碰到这样一种场景,同时打开了多个Form页面且没有隐藏Hide(),需要获取当前正在操作Avtive的页面,在被窗体调用的控件中可以使用This.ParentForm获取,但如果是普通功能类则无法使用这种方式获取,使用Form窗体静态属性Form.ActiveForm直接取值,不止为何为Nu......
  • 【电商搜索】现代工业级电商搜索技术-中科大-利用半监督学习改进非点击样本的转化率预
    【电商搜索】现代工业级电商搜索技术-中科大-利用半监督学习改进非点击样本的转化率预测0.论文信息RecSys24:UtilizingNon-clickSamplesviaSemi-supervisedLearningforConversionRatePrediction@inproceedings{huang2024utilizing,title={UtilizingNon-cli......
  • 基于Anaconda搭建深度学习环境,安装Tensorflow、Keras和Pytorch
    1、Anaconda安装(一款可以同时创建跟管理多个python环境的软件)https://blog.csdn.net/run_success/article/details/134656460安装好Anaconda之后,我们可以接着配置一个用于人工智能开发的Python环境。一、创建新的Python环境1、打开AnacondaPrompt2、创建一个名为badou的Py......
  • 【学习记录丨UVM】1.6代理人agent
    《UVM白皮书》关于agent的介绍driver和monitor处理同一协议,uvm中通常将二者封装在一起,成为一个agent。一、一个agent示例classmy_agentextendsuvm_agent;my_driverdrv;my-monitormon;`uvm_component_utils(my_agent)functionnew(stringname="my_age......
  • DIKI:清华提出基于残差的可控持续学习方案,完美保持预训练知识 | ECCV'24
    本研究解决了领域-类别增量学习问题,这是一个现实但富有挑战性的持续学习场景,其中领域分布和目标类别在不同任务中变化。为应对这些多样化的任务,引入了预训练的视觉-语言模型(VLMs),因为它们具有很强的泛化能力。然而,这也引发了一个新问题:在适应新任务时,预训练VLMs中编码的知识可能会......