ac自动机

ac自动机

安稳与你 提交于 2020-01-28 03:46:28
https://www.cnblogs.com/sclbgw7/p/9875671.html 讲的好的博客。 只有fail指针的模板,好像用不到,一般都是用last指针的模板。 void build() { queue<int>q; q.push(1); while(!q.empty()) { int x=q.front();q.pop(); for(int i=0;i<26;++i) { int c=ch[x][i]; if(!c){ch[x][i]=ch[fail[x]][i];continue;}//关键,把子节点改成fail节点的子节点 q.push(c); int fa=fail[x]; while(fa&&!ch[fa][i])fa=fail[fa]; fail[c]=ch[fa][i]; } } } https://cn.vjudge.net/contest/301351#problem/A 习题 最基础的模板,即求一个文本串有多少个匹配的模式串。 #include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 5e5 + 5; const int N = 1e6 + 5; int tree[maxn][27];

Ac自动机基础题集合

僤鯓⒐⒋嵵緔 提交于 2020-01-27 10:30:57
Ac_automaton的板子打熟以后发现碰到题不会做,而且还是比较纯的板子,只要改几处地方就可以,Ac_automation有许多优秀而fantasy的性质,下面粘几个题,来记录一下做题的心得。 1、Keywords Search 这个题最大的问题是我们很可能漏掉一些解。建Ac_automaton(Trie图),额外维护一个size变量,在单词末尾++。 然后我们拿主串在Ac_automaton上面跑,每次都遍历其fail链(及所有前缀fail),因为fail指向某个串的最长后缀,只要把size累加上,就能把可能漏掉的解全都找回来,遍历完后,size=-1,通过这个操作,我们可以保证,当一个节点被便利后,其所有可能更新答案的fail一定已经被遍历,时间复杂度更加优秀。而且照着代码画一画Trie图,发现只要把主串跑一遍,不需要别的操作,因为在Trie树的最底层,我们把空儿子已经指倒了其fail的儿子,形成一张图,这种“类环”模型可以放心大胆的把主串“扔”到Ac_automaton上“跑”一遍。 #include<iostream> #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<map> #include

【AC自动机】AC自动机

帅比萌擦擦* 提交于 2020-01-26 21:20:25
Definition & Solution AC自动机是一种多模式串的字符串匹配数据结构,核心在于利用 fail 指针在失配时将节点跳转到当前节点代表字符串的最长后缀子串。 首先对 模式串 建出一棵 tire 树,考虑树上以根节点为一个端点的每条链显然都对应着某一模式串的一个前缀子串,以下以树上的每个节点来代指从根节点到该节点对应的字符串。 定义一个字符串 \(S\) 在 trie 树上“出现过”当且仅当存在一条以根节点为一个端点的链,该链的对应字符串为 \(S\) 。 考虑对每个节点求出一个 fail 指针,该指针指向在树上出现的该子串的 最长 后缀子串的端点。考虑在匹配文本串的时候,如果某一位置失配,最优的选择显然是跳转到被匹配串的最长后缀子串。因为这样所有在树上出现过的字符串都有机会被跳转到。 需要注意的是如果一个字符串匹配到了文本串,那么他的所有后缀子串都能匹配文本串。也就是说对于一个节点,他的fail,fail的fail,一直到根节点都能匹配当前文本串。 考虑求出fail指针的方法: 设根节点为空,显然根节点的所有孩子的fail指着指向根节点。 对于一个已经求出 fail 指针的节点 \(u\) ,设 \(u\) 的 fail 指向 \(w\) ,考虑 \(u\) 的一个孩子 \(v\) ,设 \(w\) 对应的孩子为 \(z\) ,且设 \(z\) 在 trie

洛谷-P5357-【模板】AC自动机(二次加强版)

允我心安 提交于 2020-01-25 20:41:34
题目传送门 -------------------------------------- 过年在家无聊补一下这周做的几道AC自动机的模板题 sol: AC自动机,还是要解决跳fail边产生的重复访问,但是这次用last边已经不行了,只能拿76分。我们把跳fail边的过程放到串扫描完之后一次性进行。 AC自动机 #include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MAXN = 200010; struct Trie { int son[MAXN][26], fail[MAXN]; int que[MAXN]; int head, tail; int cnt[MAXN]; int tot, root; int add_node() { memset(son[tot], -1, sizeof(son[tot])); cnt[tot] = 0; return tot ++; } void init() { head = tail = 0; tot = 0; root = add_node(); } int insert(char* s) { int p = root; for (int i = 0; s[i]; i++) { int

洛谷-P3808-【模板】AC自动机(简单版)

ⅰ亾dé卋堺 提交于 2020-01-25 19:34:06
题目传送门 -------------------------------------- 过年在家无聊补一下这周做的几道AC自动机的模板题 sol: 标准AC自动机,注意不能重复跳fail边,像"aaaaaaa...aaaaaaaa"这样的数据每跳一次fail边只往上走了一层。 AC自动机 #include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MAXN = 1e6 + 10; struct Trie { int son[MAXN][26], cnt[MAXN], fail[MAXN]; int tot, root; int add_node() { int i = tot ++; memset(son[i], -1, sizeof(son[i])); cnt[i] = 0; return i; } void init() { tot = 0; root = add_node(); } void insert(char* s) { int p = root; for (int i = 0; s[i]; i++) { int index = s[i] - 'a'; if (son[p][index] == -1) son[p]

AC自动机

馋奶兔 提交于 2020-01-23 19:32:13
题源: https://www.luogu.com.cn/problem/P3796 debug了一下午发现代码又抄错了,数组大小也开错了,数据范围搞混了。。 #include <iostream> #include <stdio.h> #include <cstring> #include <queue> //#define LOCAL //#define fre #define maxn 1000005 using namespace std; char s[maxn], p[155][75]; int n; int nex[10510][26], fail[10510], e[10510], last[10510], ans[155]; //一开始这里开成了75.。。 struct Tire { int cnt; void init() { cnt = 1; memset(nex, 0xff, sizeof(nex)); memset(e, 0, sizeof(e)); memset(last, 0, sizeof(last)); } void insert(char s[], int t) { int len = strlen(s); int now = 0; for (int i = 0; i < len; ++i) { if (nex[now][s[i] - 'a']

AC自动机

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-22 21:07:11
构建字典图实现自动跳转,构建失配指针实现多模式匹配 \(fail\) 指针表示文本串在当前节点失配后,我们应该到哪个节点去继续匹配, \(u\) 的 \(fail\) 指针指向 \(v\) 表示从根到 \(v\) 的字符串为从根到 \(u\) 的字符串的最长后缀,用 \(bfs\) 来构建 \(fail\) 指针 \(fail[trie[x][i]]=trie[fail[x]][i]\) 相当于在 \(x\) 和 \(fail[x]\) 后面加一个字符 \(i\) ,就构成 \(fail[trie[x][i]]\) 若发现 \(trie[x][i]\) 不存在,则直接将其 \(trie[fail[x]][i]\) 赋值给它,来实现一个类似于路径压缩的操作 \(code\) : void insert(char *str) { int len=strlen(str),cur=0; for(int i=0;i<len;++i) { int ch=str[i]-'a'; if(!trie[cur][ch]) trie[cur][ch]=++tot; cur=trie[cur][ch]; } num[cur]++; } void build() { queue<int> q; for(int i=0;i<26;++i) if(trie[0][i]) q.push(trie[0][i]);

HDU 2222 Keywords Search [AC自动机]

微笑、不失礼 提交于 2020-01-22 11:45:48
Problem Description In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey also wants to bring this feature to his image retrieval system. Every image have a long description, when users type some keywords to find the image, the system will match the keywords with description of image and show the image which the most keywords be matched. To simplify the problem, giving you a description of image, and some keywords, you should tell me how many keywords will be match. Input First line will contain one integer means how many cases will follow by. Each

AC自动机【模板】+经典例题

﹥>﹥吖頭↗ 提交于 2020-01-17 23:54:09
AC自动机模板 经典例题 Keywords Search HDU - 2222 【求目标串中出现了几个模式串】 【(注意:模式串可能会重复)】 模板: 1 const int maxn=26; 2 struct Trie 3 { 4 int next[500010][maxn]; 5 int fail[500010],end[500010]; 6 int root,L; 7 int newnode() //初始化 8 { 9 for(int i=0;i<26;i++) 10 next[L][i]=-1; 11 end[L++]=0; 12 return L-1; 13 } 14 15 void init()//初始化 16 { 17 L=0; 18 root=newnode(); 19 } 20 void insert(char s[])//构造树trie 21 { 22 int len=strlen(s); 23 int now=root; 24 for(int i=0;i<len;i++) 25 { 26 if(next[now][s[i]-'a']==-1) 27 next[now][s[i]-'a']=newnode(); 28 now=next[now][s[i]-'a']; 29 } 30 end[now]++; 31 } 32 33 void build()/

trie树 & ac自动机

拟墨画扇 提交于 2020-01-17 01:37:09
trie树 trie树就是字典树,可以理解为单词树,树上每条边是字母,被标记的节点表示根到这个节字母组成了单词。 数据结构:用二维数组trie[maxn][N],tire[u][c]表示树上编号为u的父节点以边为c单词连接到的儿子的编号。 创建trie树:每次添加一个单词,若当前路径已建立此以连接此单词为边的儿子节点就沿着走,否则建立新的节点。 学习链接: 浅谈Trie树 Trie树模板 const int maxn = 5e5 + 7 ; const int N = 26 ; struct Tire { int trie [ maxn ] [ N ] , tot ; bool book [ maxn ] ; void Init ( ) { memset ( trie , 0 , sizeof trie ) ; memset ( book , 0 , sizeof book ) ; tot = 0 ; } void Insert ( string a ) { int u = 0 ; for ( int i = 0 ; i < a . size ( ) ; ++ i ) { int v = a [ i ] - 'a' ; if ( trie [ u ] [ v ] == 0 ) { trie [ u ] [ v ] = ++ tot ; } u = trie [ u ] [ v ]