luogu P3796【模板】AC自动机(加强版)

嘟嘟嘟

这个和某谷的AC自动机模板简单版差不多。

但还是要注意几点的:

1.这个是统计出现次数,而不是是否出现,所以在查询的时候加上这个节点的val后,不能把val标记为-1。那么也就可以说查询的时间复杂度能比简单版的稍微第一慢一点。

2.考虑k个一样的模式串:刚开始我想的是每一个节点开一个vector,记录这里是第几个模式串。但其实没有这个必要,对于相同的模式串,我们只用记录任意一个就行,反而在出现次数上要都加上。因为如果主串中存在这些相同的模式串,那么出现次数应该是出现次数 * k。输出的时候如果是这些串最多,那么都应该把这些输出。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<stack>
  9 #include<queue>
 10 #include<vector>
 11 using namespace std;
 12 #define enter puts("")
 13 #define space putchar(‘ ‘)
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 1e6 + 5;
 21 const int maxm = 1.05e4 + 5;
 22 inline ll read()
 23 {
 24   ll ans = 0;
 25   char ch = getchar(), las = ‘ ‘;
 26   while(!isdigit(ch)) las = ch, ch = getchar();
 27   while(isdigit(ch)) ans = ans * 10 + ch - ‘0‘, ch = getchar();
 28   if(las == ‘-‘) ans = -ans;
 29   return ans;
 30 }
 31 inline void write(ll x)
 32 {
 33   if(x < 0) putchar(‘-‘), x = -x;
 34   if(x >= 10) write(x / 10);
 35   putchar(x % 10 + ‘0‘);
 36 }
 37
 38 int n;
 39 char s[maxn], ss[155][75];
 40
 41 int sum[155];
 42 int ch[maxm][26], val[maxm], pos[maxm], f[maxm], cnt = 0;
 43 int getnum(char c)
 44 {
 45   return c - ‘a‘;
 46 }
 47 void insert(int id, char *s)
 48 {
 49   int m = strlen(s);
 50   int now = 0;
 51   for(int i = 0; i < m; ++i)
 52     {
 53       int c = getnum(s[i]);
 54       if(!ch[now][c]) ch[now][c] = ++cnt;
 55       now = ch[now][c];
 56     }
 57   val[now]++; pos[now] = id;
 58 }
 59 void build()
 60 {
 61   queue<int> q;
 62   for(int i = 0; i < 26; ++i) if(ch[0][i]) q.push(ch[0][i]);
 63   while(!q.empty())
 64     {
 65       int now = q.front(); q.pop();
 66       for(int i = 0; i < 26; ++i)
 67     {
 68       if(ch[now][i]) f[ch[now][i]] = ch[f[now]][i], q.push(ch[now][i]);
 69       else ch[now][i] = ch[f[now]][i];
 70     }
 71     }
 72 }
 73 void query(char *s)
 74 {
 75   int m = strlen(s), now = 0;
 76   for(int i = 0; i < m; ++i)
 77     {
 78       int c = getnum(s[i]);
 79       now = ch[now][c];
 80       for(int j = now; j; j = f[j]) sum[pos[j]] += val[j];
 81     }
 82 }
 83
 84 void init()
 85 {
 86   Mem(ch, 0); Mem(val, 0); Mem(pos, 0); Mem(f, 0);
 87   Mem(sum, 0);
 88   cnt = 0;
 89 }
 90
 91 int main()
 92 {
 93   while(scanf("%d", &n) && n)
 94     {
 95       init();
 96       for(int i = 1; i <= n; ++i)
 97     {
 98       scanf("%s", ss[i]);
 99       insert(i, ss[i]);
100     }
101       build();
102       scanf("%s", s);
103       query(s);
104       int Max = -1;
105       for(int i = 1; i <= n; ++i) Max = max(Max, sum[i]);
106       write(Max); enter;
107       for(int i = 1; i <= n; ++i) if(sum[i] == Max) printf("%s\n", ss[i]);
108     }
109   return 0;
110 }

原文地址:https://www.cnblogs.com/mrclr/p/9768532.html

时间: 2024-11-08 21:43:46

luogu P3796【模板】AC自动机(加强版)的相关文章

算法模板——AC自动机

实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有时候字典会相当稀疏,所以引入了chi和bro指针进行优化——其原理比较类似于邻接表,这个东西本身和next数组本质上是一致的,只是chi和bro用于遍历某一节点下的子节点,next用于查询某节点下是否有需要的子节点) 1 type 2 point=^node; 3 node=record 4 ex:

[模板]AC自动机(1)

题目描述 给定一个文本串和多个模式串,求有几个模式串出现在文本串中 #include <cstdio> #include <cstring> #include <algorithm> #define MAXN 1000005 char s[MAXN]; int N; struct queue{ int que[MAXN];int head,tail; queue():head(1),tail(0){} inline void pop(){head++;} inline

模板——AC自动机

#include<bits/stdc++.h> using namespace std; struct nob{ int fail,son[27],ed; }a[1000000]; int cnt=0; void build (string s){ int now=0; for (int i=0; i<s.length(); i++){ if (a[now].son[s[i]-'a']==0) a[now].son[s[i]-'a']=++cnt; now=a[now].son[s[i]

AC自动机例题

P3808 [模板]AC自动机(简单版) [题目描述] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. #include<bits/stdc++.h> using namespace std; typedef long long LL; const int INF=1e9+7; inline LL read(){ register LL x=0,f=1;register char c=getchar(); while(c<48||c>57){if(c=='-')f=

【题解】P3796【模板】AC自动机(加强版)

[题解]P3796 [模板]AC自动机(加强版) 记录当前\(cnt\)是第几个"星".记录第几个串是对应着第几个星. 这里补充一点对于\(AC\)自动机的理解.可能一直有个问题我没有想明白,就是打标记的点只有一个,然而匹配时,假若一个分支包括了另一个不同的分支该怎么办.实际上,我们可以在匹配的时候使用\(fail\)数组进行类似链式前向星的遍历,从而遍历到那个打标记的地方.那么问题来了,怎么保证链式前向星会遍历到那个打了标记的节点呢?答案就在\(gen\_fail\)的玄机里.\(g

P3796 【模板】AC自动机(加强版)

题目描述 有个由小写字母组成的模式串以及一个文本串.每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据. 每组数据的第一行为一个正整数,表示共有个模式串,. 接下去行,每行一个长度小于等于的模式串.下一行是一个长度小于等于的文本串. 输入结束标志为. 输出格式: 对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列. 输入输出样例 输入样例#1: 2 aba bab a

P3796 【模板】AC自动机(加强版) 题解(Aho-Corasick Automation)

题目链接 AC自动机 解题思路 AC自动机模板题. 刚学AC自动机,写一篇博客增强理解. AC自动机最关键的一点在于,\(fail\)失配指针的构造. \(fail\)指针指向的地方,是匹配出现错误后进行重新匹配的位置,这说明,从根开始到\(fail\)指针指向的地方这一块字符串,正是我们刚刚失配之前配上的那一块字符串(子串),且为最长子串.这一点和KMP算法相同. AC代码 #include<stdio.h> #include<string.h> int ac[100010][2

luogu P3808 【模板】AC自动机(简单版)

二次联通门 : luogu P3808 [模板]AC自动机(简单版) /* luogu P3808 [模板]AC自动机(简单版) 手速越来越快了 10分钟一个AC自动机 一遍过编译 + 一边AC 感觉不错 我也就做做板子题了.. */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define Max 1000009 void read (int &

LG5357 「模板」AC自动机(二次加强版) AC自动机+fail树

问题描述 LG5357 题解 不是fail树的AC自动机复杂度是假的. 把AC自动机搞出来,建立Trie树,树上爆搜一遍就好了. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; template <typename Tp> void read(Tp &x){ x=0;char ch=1;int fh; while(ch!='-'&&(ch>'9'||ch<'0')) c