hdu2222 Keywords Search AC自动机学习小结

2024-04-02 10:48

本文主要是介绍hdu2222 Keywords Search AC自动机学习小结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门:http://http://acm.hdu.edu.cn/showproblem.php?pid=2222

思路:AC自动机入门题,直接上AC自动机即可。


对于构建AC自动机,我们要做的只有三件事:

1)构建字典树

2)构建失败指针

3)构建trie图(这道题好像不做这一步也能A。。。但是这一步不做是会被卡成O(n^2)的。。。)


1)第一步还是比较好理解的

根是虚根,边代表字母,那么根到终止节点的路径就是一个字符串,这样对于前缀相同的字符串我们就可以省下存公共前缀的空间。

加入一个模式串,我们就在trie树上一步一步走,没有这个儿子就新建,否则就按原来的边走。


2)第二步有一点复杂。

学AC自动机要有KMP的基础原因就在这里。fail指针就是KMP的next数组在有多个模式串时的升级版

KMP的next数组是指同一个模式串中,既是最长前缀又是后缀的子串的长度,这么定义是为了方便在匹配失败时跳转

而fail指针的作用也是为在匹配失败时跳转。因为是多串,一个点的fail指针指向与这一段的后缀相同的,另一个串前缀,这样就实现了在匹配失败时跳转。画个图更直观


然后就是求出fail指针了。求next数组时,我们可以由之前的next数组进行跳转得到现在的next数组,求fail指针也很类似。

我们可以一层一层地用bfs求出fail指针。

1.根节点的fail指向null,根节点的子节点的fail指向根(因为第一位就不匹配了,当然要重新开始)

2.求完fail的放到队尾

3.取出队头节点x,求它的所有儿子ch[x][i]的fail指针

如果ch[x][i]存在,那么fail[ch[x][i]]=ch[fai[x]][i](其实应该一直跳fail直到ch[x][i]存在,这也是不构建trie图会被卡成O(n^2)的原因,把不存在的儿子补好后,就只要跳一次了)

否则ch[x][i]=ch[fail[x]][i](其实就是第三步构建trie图,把所有不存在的儿子补好,省得每次跳很多次fail)

4.重复2和3直到队列为空

这样,AC自动机就构建好了


然后就是代码了。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn=1000010,maxm=250010;
using namespace std;
int cas,n;char s[maxn];struct AC_DFA{int tot,ch[maxm][26],fai[maxm],sum[maxm],q[maxm],head,tail;void clear(){tot=0,memset(ch,0,sizeof(ch)),memset(fai,0,sizeof(fai)*2);}void insert(){int p=0;for (int i=1;s[i];p=ch[p][s[i]-'a'],i++) if (!ch[p][s[i]-'a']) ch[p][s[i]-'a']=++tot;sum[p]++;}void getfail(){head=0,q[tail=1]=0,fai[0]=-1;while (head!=tail){int x=q[++head];for (int i=0;i<26;i++)if (ch[x][i]){q[++tail]=ch[x][i];int p=x==0?0:ch[fai[x]][i];//while (p!=-1&&!ch[p][i]) p=fai[p];fai[ch[x][i]]=p;}else ch[x][i]=x==0?0:ch[fai[x]][i];}}void work(){int ans=0;for (int i=1,p=0;s[i];i++){while (p&&!ch[p][s[i]-'a']) p=fai[p];p=ch[p][s[i]-'a'];for (int t=p;t;t=fai[t]) ans+=sum[t],sum[t]=0;//printf("%d %d\n",t,sum[t]),}printf("%d\n",ans);}
}T;int main(){scanf("%d",&cas);while (cas--){scanf("%d",&n);T.clear();for (int i=1;i<=n;i++)scanf("%s",s+1),T.insert();T.getfail(),scanf("%s",s+1),T.work();}return 0;
}


这篇关于hdu2222 Keywords Search AC自动机学习小结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/869782

相关文章

MySQL中VARCHAR和TEXT的区别小结

《MySQL中VARCHAR和TEXT的区别小结》MySQL中VARCHAR和TEXT用于存储字符串,VARCHAR可变长度存储在行内,适合短文本;TEXT存储在溢出页,适合大文本,下面就来具体的了解... 目录一、VARCHAR 和 TEXT 基本介绍1. VARCHAR2. TEXT二、VARCHAR

全网最全Tomcat完全卸载重装教程小结

《全网最全Tomcat完全卸载重装教程小结》windows系统卸载Tomcat重新通过ZIP方式安装Tomcat,优点是灵活可控,适合开发者自定义配置,手动配置环境变量后,可通过命令行快速启动和管理... 目录一、完全卸载Tomcat1. 停止Tomcat服务2. 通过控制面板卸载3. 手动删除残留文件4.

Python打包成exe常用的四种方法小结

《Python打包成exe常用的四种方法小结》本文主要介绍了Python打包成exe常用的四种方法,包括PyInstaller、cx_Freeze、Py2exe、Nuitka,文中通过示例代码介绍的非... 目录一.PyInstaller11.安装:2. PyInstaller常用参数下面是pyinstal

python中getsizeof和asizeof的区别小结

《python中getsizeof和asizeof的区别小结》本文详细的介绍了getsizeof和asizeof的区别,这两个函数都用于获取对象的内存占用大小,它们来自不同的库,下面就来详细的介绍一下... 目录sys.getsizeof (python 内置)pympler.asizeof.asizeof

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

mybatis映射器配置小结

《mybatis映射器配置小结》本文详解MyBatis映射器配置,重点讲解字段映射的三种解决方案(别名、自动驼峰映射、resultMap),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定... 目录select中字段的映射问题使用SQL语句中的别名功能使用mapUnderscoreToCame

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.