P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)
P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)
传送门
形式上,AC 自动机基于由若干模式串构成的 Trie 树,并在此之上增加了一些 fail 边;本质上,AC 自动机是一个关于若干模式串的DFA(确定有限状态自动机),接受且仅接受以某一个模式串作为后缀的字符串。 并且,与一般自动机不同的,AC 自动机还有关于某个模式串的接受状态,也就是与某个模式串匹配(以某个模式串为后缀)的那些状态,即某个模式串在 Trie树上的终止节点在 fail 树上的整个子树。
暴力跳 fail 边,会被类似于 aaaaa……aaaaa 这样的串卡掉。
正确的做法是建出 fail 树,记录自动机上的每个状态被匹配了几次,最后求出每个模式串在 Trie 上的终止节点在 fail 树上的子树总匹配次数就可以了,我们dfs建立好的fail树,从当前结点的失配指针指向的结点向该结点连边建fail树,这样我们dfs该树的时候可以保证每一条边(u,v)(u,v)(u,v),u到根节点之间的串等于v到根节点之间的串,那么该串的出现次数就是所有的边(u,v)(u,v)(u,v),的size之和。不会加重, 因为fail树是由fail指针边构成的,然而所有的点只会建立一个fail指针。例如有三个相同的模式串,只会有两个fail指针。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>using namespace std;const int N = 200010, S = 2000010;queue<int>q;
struct trie{int fail;int vis[26];int ed;
}ac[N];int match[N];
int n;
int tot, sizes[N];
int head[N], nex[N], ver[N], cnt, num;void add(int x, int y){ver[cnt] = y;nex[cnt] = head[x];head[x] = cnt ++ ;
}void insert(int x, char s[]){int len = strlen(s);int p = 0;//根从0开始for(int i = 0; i < len; ++ i){int ch = s[i] - 'a';if(!ac[p].vis[ch])ac[p].vis[ch] = ++ tot;p = ac[p].vis[ch];}ac[p].ed ++ ;match[x] = p;//记录每个模式串在 Trie 树上的终止节点
}void get_fail(){for(int i = 0;i < 26; ++ i){if(ac[0].vis[i]){ac[ac[0].vis[i]].fail = 0;q.push(ac[0].vis[i]);}}while(q.size()){int p = q.front();q.pop();for(int i = 0;i < 26; ++ i){if(ac[p].vis[i]){ac[ac[p].vis[i]].fail = ac[ac[p].fail].vis[i];q.push(ac[p].vis[i]);}else ac[p].vis[i] = ac[ac[p].fail].vis[i];}}
}void dfs(int x){for(int i = head[x]; ~i; i = nex[i]){int y = ver[i];dfs(y);sizes[x] += sizes[y];}
}int ac_query(char s[]){int p = 0, ans = 0;int len = strlen(s);for(int i = 0;i < len;++i){//!计算有多少个单词在文本中出现p = ac[p].vis[s[i]-'a'];//往下一层走for(int k = p;k&&ac[k].ed!=-1;k = ac[k].fail){ans += ac[k].ed;ac[k].ed = -1;}}p = 0;for(int i = 0; i < len; ++ i){p = ac[p].vis[s[i] - 'a'];sizes[p] ++ ;//!记录匹配次数}for(int i = 1; i <= tot; ++ i)//!建fail树add(ac[i].fail, i);dfs(0);//!统计子树和for(int i = 1;i <= n; ++ i)printf("%d\n", sizes[match[i]]);return ans;
}char s[S];int main(){scanf("%d", &n);memset(head, -1, sizeof head);for(int i = 1;i <= n; ++ i){scanf("%s", s);insert(i, s);}//cout << "ok" << num ++ << endl;get_fail();//cout << "ok" << num ++ << endl;scanf("%s", s);//cout << "ok" << num ++ << endl;int res = ac_query(s);//cout << res << endl;return 0;
}
P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)相关推荐
- bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 3521 Solved: 1913 [Submit][S ...
- CodeForces - 1437G Death DBMS(AC自动机fail树上树链剖分建线段树/暴跳fail)
题目链接:点击查看 题目大意:给出 n 个模式串,每个模式串初始时的权值为 0,然后有 m 次操作: 1 i x:将第 i 个模式串的权值修改为 x 2 s:给出一个字符串 s,询问字符串 s 作为主 ...
- 洛谷P5357 - 【模板】AC自动机(二次加强版)(AC自动机+fail树)
题目链接:点击查看 题目大意:给出n个模式串,问在主串中分别出现了多少次 题目分析:如果像以往那样,在匹配的时候fail指针乱跳的话,那么是错误的AC自动机使用方法,时间复杂度也大大上升,接近于暴力的 ...
- 【数据结构】自动机全家桶(AC、回文、后缀自动机)
自动机全家桶 前言 一.AC自动机 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 6.代码模板 二.回文自动机(回文树) 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 2545 Solved: 1419 [Submit][S ...
- AC自动机 - 多模式串的匹配 --- HDU 3695 Computer Virus on Planet Pandora
Problem's Link Mean: 有n个模式串和一篇文章,统计有多少模式串在文章中出现(正反统计两次). analyse: 好久没写AC自动机了,回顾一下AC自动机的知识. 本题在构造文章的时 ...
- HDU 4787 在线AC自动机 分块(模式串和母串交叉给出,多次求getFail)
题意: 给定T个测试数据 n个操作 + 插入单词 ? 询问母串中有多少个子串 在上面出现过 ( 子串被加密,即←移动L位 (L为上次询问的答案) ) 分块思路: 因为模式串和母串交叉给出,正常来说应该 ...
- Xamarin XAML语言教程模板视图TemplatedView(二)
Xamarin XAML语言教程模板视图TemplatedView(二) (2)打开MainPage.xaml文件,编写代码,将构建的控件模板应用于中TemplatedView.代码如下: <? ...
- GIS实战应用案例100篇(二)-元胞自动机模拟城市扩张过程
前言 CA模型:CA(Cellular Automat)即元胞自动机模型,元胞自动机是一种具有时空计算特征的模型框架,从局部到整体的建模思想被广泛的应用于空间上离散.时间上也离散的复杂性系统模拟.标准 ...
最新文章
- SEO那些事:一句代码一键分享网站
- JavaScript之match()方法讲解
- 请简单解释一下ARP协议和ARP攻击
- Convert(varchar(8),Getdate(),108) 什么意思
- ISE报错问题集锦(转载)
- ansys命令流_ANSYS命令流建模3之划分单元+施加弹簧
- 关于myeclipse输入法编程繁体的修正
- 在PHP中对象真的是按引用传递的吗
- python自助电影售票机_手把手教你用python抢票回家过年(代码简单)
- samba配置过程(附网络凭据的解决方法)
- c语言 自定义strcmp
- vim 模式下的几个快捷用法
- Oracle OAF 学习小结(1)- 个性化详解
- 叶俊|从人类基因本能谈到赞美的力量|麻辣总裁幽默SHOW嗨翻全场
- 给大家分享一篇 用Python抓取漫画并制作mobi格式电子书
- 苹果签名是什么?苹果签名的作用是什么?
- python基础知识大一总结与反思_反思总结及规划 其一
- 简单整系数滤波器去除心电信号的基线漂移
- 教师资格证计算机科目有哪些内容,初中教师资格证考试科目及内容有哪些?
- HTML基础的回顾复习(基本标签,简单的一个登陆验证)