P3796 【模板】AC自动机(加强版) 题解(Aho-Corasick Automation)
题目链接
解题思路
AC自动机模板题。
刚学AC自动机,写一篇博客增强理解。
AC自动机最关键的一点在于,\(fail\)失配指针的构造。
\(fail\)指针指向的地方,是匹配出现错误后进行重新匹配的位置,这说明,从根开始到\(fail\)指针指向的地方这一块字符串,正是我们刚刚失配之前配上的那一块字符串(子串),且为最长子串。这一点和KMP算法相同。
AC代码
#include<stdio.h>
#include<string.h>
int ac[100010][26],cnt=1;
int queue[100010],fail[100010],end[100010];
char a[160][75],m[1000010];
struct {
int num,cnt;
}ans[500],temp;
void push(char a[],int l,int num){//建立trie树,很好理解不再赘述
int i,now=0;
for(i=0;i<l;i++){
int v=a[i]-'a';
if(!ac[now][v])ac[now][v]=cnt++;
now=ac[now][v];
}
end[now]=num;
}
void build(){
int head=0,tail=0,i;//C党手写queue
for(i=0;i<26;i++)if(ac[0][i]){
queue[tail++]=ac[0][i];//push
fail[ac[0][i]]=0;
}
while(head<tail){
int v=queue[head++];//pop
for(i=0;i<26;i++){
if(ac[v][i]){
fail[ac[v][i]]=ac[fail[v]][i];
queue[tail++]=ac[v][i];//push
}
else ac[v][i]=ac[fail[v]][i];
//该节点的失配指针,指向该节点的父节点的失配指针所指向的节点的子节点
//也即,假设ac[v][i]的父节点失配指针指向的节点为E,则
//从根节点到E的这个串,为从根节点到v这个串的最长共同结尾子串
//那么,ac[v][i]的失配指针应当指向E的第i个节点(保证这一位字符相同)
//if和else的作用:一个是失配指针,一个是trie图。
//如果这点没有后续了,只能建立trie图。
//否则,应当建立失配指针。
}
}
}
void query(char a[],int l){
int i,j,now=0;
for(i=0;i<l;i++){
now=ac[now][a[i]-'a'];//沿着建立好的trie图走
for(j=now;j;j=fail[j])ans[end[j]].cnt++;//找到单词末尾并存储个数
}
}
//C党手写快排
int cmp(int x,int y){
if(ans[x].cnt>ans[y].cnt)return 1;
if(ans[x].cnt<ans[y].cnt)return 0;
if(ans[x].num<ans[y].num)return 1;
return 0;
}
void qs(int left,int right){
int i=left,j=right;
if(i>=j)return;
while(i!=j){
for(;i<j;j--)if(cmp(j,left))break;
for(;i<j;i++)if(cmp(left,i))break;
if(i!=j){
temp=ans[i];ans[i]=ans[j];ans[j]=temp;
}
}
j=left;
temp=ans[i];ans[i]=ans[j];ans[j]=temp;
qs(left,i-1);
qs(i+1,right);
}
int main(){
int i,n;
while(scanf("%d",&n)){
if(!n)break;
cnt=1;
for(i=1;i<=n;i++){
scanf("%s",a[i]);
push(a[i],strlen(a[i]),i);//建立trie树
ans[i].num=i;
ans[i].cnt=0;
}
build();//构造AC自动机的fail指针,以及完善trie树成为trie图
scanf("%s",m);
query(m,strlen(m));//询问文本串
//以下为本题特色,不是AC自动机精髓,可跳过
qs(1,n);
printf("%d\n",ans[1].cnt);
printf("%s\n",a[ans[1].num]);
for(i=2;i<n;i++){
if(ans[i].cnt-ans[i-1].cnt)break;
printf("%s\n",a[ans[i].num]);
}
memset(end,0,sizeof(int)*cnt);
memset(fail,0,sizeof(int)*cnt);
memset(ac,0,sizeof(ac));
}
return 0;
}
P3796 【模板】AC自动机(加强版) 题解(Aho-Corasick Automation)的更多相关文章
- luoguP3796[模板]AC自动机(加强版)
传送门 ac自动机模板,可能我写的ac自动机是有点问题的,所以跑的有些慢 暴力跳fail统计 代码: #include<cstdio> #include<iostream> # ...
- HDU 2222 Keywords Search(AC自动机)题解
题意:给你几个keywords,再给你一段文章,问你keywords出现了几次. 思路:这里就要用到多模匹配算法AC自动机了,AC自动机需要KMP和字典树的知识,匹配时是在字典树上,失配我们就要用到类 ...
- luoguP3808[模板]AC自动机(简单版)
传送门 ac自动机模板题,裸的多串匹配 代码: #include<cstdio> #include<iostream> #include<algorithm> #i ...
- 算法模板——AC自动机
实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...
- 模板 AC自动机
题目描述 有$N$ 个由小写字母组成的模式串以及一个文本串$T$ .每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串$T$ 中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据 ...
- 算法竞赛模板 AC自动机
AC自动机基本操作 (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针. (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思 ...
- [模板][P3796]AC自动机(加强版)
Description: 输出有哪些模式串在文本串中出现次数最多,这个次数是多少 Hint: 多组数据,$ len_{文本串}<=10^6,\sum len_{模式串} <= 70*150 ...
- 【模板】AC自动机加强版
题目大意:给定 N 个模式串和一个文本串,求每个模式串在文本串中出现的次数. 题解:文本串在自动机上匹配的过程中,记录下自动机上每一个状态被访问的次数.对于访问到的节点 i,则状态 i 的后缀中存在的 ...
- 洛谷.3808/3796.[模板]AC自动机
题目链接:简单版,增强版 简单版: #include <cstdio> #include <cstring> const int N=1e6+5,S=26; char s[N] ...
- HDU 3065 病毒侵袭持续中(AC自动机)题解
题意:要你找到主串中每个模式串的个数. 思路:题目都没说是多组数据,结果没while(~)直接WA了,和上一题差不多,可以用map或者开个数组储存.指针要记得回收内存,不然MLE. #include& ...
随机推荐
- ElasticSearch 交互使用
Curl 命令 # 建立索引 [root@dbtest01 ~]# curl -XPUT 'http://10.0.0.121:9200/test' # 插入数据 [root@dbtest01 ~]# ...
- 数据库之ODPS中sql语句指南
此篇博文为本人在实际工作中应用总结,转载请注明出处. 持续更新中 一.增 1.增加一列(向csp_hsy_count_info表中增加sale_qty列) ALTER TABLE csp_hsy_co ...
- codeforces 1010 C. Border【exgcd】
题目链接:戳这里 学习博客:戳这里 题意:给n种数,n种数取任意个任意组合相加为sum,求sum%k有哪些值. 解题思路: 由exgcd可知(具体用到的是贝祖定理),ax + by = c,满足gcd ...
- c++ 输出文件夹(不包括子文件夹)中后缀文件
参考:_finddata_t结构体用法 - 麒麒川的博客 - CSDN博客 准备知识部分: MessageBox MessageBox function (winuser.h) | Microsoft ...
- cookie,session,token之间的联系与区别
发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议, 就是请求加响应, 尤其是我不用 ...
- C++中main函数的返回值一定要是int
因为大学上课时候,经常是在主函数中做处理,直接用cout语句输出到显示设备,所以一直在用void main(). 直到后面具体编程的时候,才发现void main()这种用法是按 C89(C语言的早期 ...
- 计组CPU设计实验关键材料和关键设计
我记得这是2016春季学期搞得,参考和学习了很多别人的东西,这里小小的总结一下,逻辑性还不是太强,还需要好好整理 首先是指令集 CPU架构 外部接线架构 指令格式 机器状态自动机 这部分忘了,汗 这部 ...
- Web 前端如何一键开启上帝模式
Web 前端如何一键开启上帝模式 God Mode document.designMode = `on`; refs https://www.cnblogs.com/xgqfrms/tag/desig ...
- The best Fibonacci is achieved in js
The best Fibonacci is achieved in js the best realized by using js 斐波那契数列 "use strict"; /* ...
- ThoughtWorks Homework
ThoughtWorks Homework Homework 考察知识点 项目搭建 技术选型 测试 编码风格 代码质量 设计模式 数据结构 算法 架构 开源协作 CI/CD DevOps Linux ...