洛谷.3808/3796.[模板]AC自动机
简单版:
#include <cstdio>
#include <cstring>
const int N=1e6+5,S=26;
char s[N];
struct AC_Automaton
{
int cnt,q[N],val[N],fail[N],las[N],son[N][S];
// struct Node
// {
// int val,las,fail,son[S];
// Node *son[S];//指针太麻烦了。。
// Node() {val=las=0, memset(son,0,sizeof son);}
// }pool[N];
void Insert(char *s)
{
int l=strlen(s),u=0;
for(int v,i=0; i<l; ++i)
{
v=s[i]-'a';
if(!son[u][v]) son[u][v]=++cnt;
u=son[u][v];
}
++val[u];
}
void Build()
{
int h=0,t=0;
for(int i=0; i<S; ++i)
if(son[0][i]) fail[son[0][i]]=0,q[t++]=son[0][i];
while(h<t)
{
int x=q[h++];
for(int v,i=0; i<S; ++i)
if(son[x][i])
fail[v=son[x][i]]=son[fail[x]][i], q[t++]=v, las[v]=val[fail[v]]?fail[v]:las[fail[v]];
else son[x][i]=son[fail[x]][i];
}
}
int Query(char *s)
{
int l=strlen(s),res=0,u=0;
for(int i=0; i<l; ++i)
{
u=son[u][s[i]-'a'];
for(int p=u; p&&~val[p]; p=las[p])
res+=val[p], val[p]=-1;
}
return res;
}
}ac;
int main()
{
int n; scanf("%d",&n);
while(n--) scanf("%s",s), ac.Insert(s);
ac.Build();
scanf("%s",s), printf("%d",ac.Query(s));
return 0;
}
增强版:1920ms(1268ms) 我说怎么慢。。数组开太大了
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=10505,S=26;
int n;
char s[155][75],p[1000005];
struct AC_Automaton
{
int cnt,q[N],val[N],fail[N],las[N],son[N][S],tm[155];
void Init()
{
cnt=0, memset(son,0,sizeof son), memset(val,0,sizeof val);
}
void Insert(char *s,int id)
{
int l=strlen(s),u=0;
for(int v,i=0; i<l; ++i)
{
v=s[i]-'a';
if(!son[u][v]) son[u][v]=++cnt;
u=son[u][v];
}
val[u]=id;
}
void Build()
{
int h=0,t=0;
for(int i=0; i<S; ++i)
if(son[0][i]) fail[son[0][i]]=0,q[t++]=son[0][i];
while(h<t)
{
int x=q[h++];
for(int v,i=0; i<S; ++i)
if(son[x][i])
fail[v=son[x][i]]=son[fail[x]][i], q[t++]=v, las[v]=val[fail[v]]?fail[v]:las[fail[v]];
else son[x][i]=son[fail[x]][i];
}
}
void Query(char *p)
{
memset(tm,0,sizeof tm);
int l=strlen(p),u=0,res=0;
for(int i=0; i<l; ++i)
{
u=son[u][p[i]-'a'];
for(int p=u; p; p=las[p])
++tm[val[p]];
}
for(int i=1; i<=n; ++i) res=std::max(res,tm[i]);
printf("%d\n",res);
for(int i=1; i<=n; ++i)
if(tm[i]==res) printf("%s\n",s[i]);
}
}ac;
int main()
{
while(scanf("%d",&n),n)
{
ac.Init();
for(int i=1; i<=n; ++i) scanf("%s",s[i]), ac.Insert(s[i],i);
ac.Build();
scanf("%s",p), ac.Query(p);
}
return 0;
}
增强版 第二次写(2018.4.5):1700ms(1204ms)
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
const int N=152*72,S=26;
int n;
char s[152][72],p[1000005];
struct AC_Automaton
{
int tot,son[N][27],fail[N],val[N],las[N],q[N],tm[152];
void Init(){
tot=0, memset(son,0,sizeof son), memset(val,0,sizeof val);
}
void Insert(char *s,int pos)
{
int l=strlen(s),x=0;
for(int id,i=0; i<l; ++i)
{
id=s[i]-'a';
if(!son[x][id]) son[x][id]=++tot;
x=son[x][id];
}
val[x]=pos;
}
void Build()
{
int h=0,t=0;
for(int i=0; i<S; ++i)
if(son[0][i]) fail[son[0][i]]=0,q[t++]=son[0][i];
while(h<t)
{
int x=q[h++];
for(int v,i=0; i<S; ++i)
if(son[x][i])
fail[v=son[x][i]]=son[fail[x]][i],q[t++]=v,las[v]=val[fail[v]]?fail[v]:las[fail[v]];
else son[x][i]=son[fail[x]][i];
}
}
void Query(char *p)
{
int l=strlen(p),res=0,x=0;
memset(tm,0,sizeof tm);
for(int i=0; i<l; ++i)
{
x=son[x][p[i]-'a'];
for(int j=x; j; j=las[j]) ++tm[val[j]];
}
for(int i=1; i<=n; ++i) if(res<tm[i]) res=tm[i];
printf("%d\n",res);
for(int i=1; i<=n; ++i) if(tm[i]==res) printf("%s\n",s[i]);
}
}ac;
int main()
{
while(scanf("%d",&n),n){
ac.Init();
for(int i=1; i<=n; ++i) scanf("%s",s[i]),ac.Insert(s[i],i);
ac.Build(), scanf("%s",p), ac.Query(p);
}
return 0;
}
洛谷.3808/3796.[模板]AC自动机的更多相关文章
- [洛谷3808]【模板】AC自动机(简单版)
题目大意: 给定$n$个模式串$p(\sum|p_i|\le10^6)$和一个$t(|t|\le10^6)$,求在$t$中被匹配的$p$的个数. 思路: AC自动机模板题,注意$t$中一个字符可能对应 ...
- 洛谷P3966 [TJOI2013]单词(AC自动机)
题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入输出格式 输入格式: 第一行一个整数N,表 ...
- 洛谷P3966 单词 [TJOI2013] AC自动机
正解:AC自动机 解题报告: 传送门! 先来提供一个40pts错解QAQ 首先看到这题就会想到AC自动机板子题2鸭!然后就照着那题的套路打一下,随便改一点儿,简单来说就是每次经过一个节点都要++,然后 ...
- 洛谷P2444 病毒 [POI2000] AC自动机
正解:AC自动机 解题报告: 传送门! 首先看到这种题目二话不说先把trie树和fail指针建立起来 然后就想鸭,如果我们想让模式串和文本串尽量不能匹配,就要想办法让它跳fail指针,而不是继续往下走 ...
- 洛谷P2444 病毒【AC自动机】
题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...
- 洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)
要点 这是一道蔡队题,看我标题行事 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀.又有每个Trie节点的 ...
- 洛谷 P3370 【模板】字符串哈希
洛谷 P3370 [模板]字符串哈希 题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的 ...
- 洛谷P3369 【模板】普通平衡树(Treap/SBT)
洛谷P3369 [模板]普通平衡树(Treap/SBT) 平衡树,一种其妙的数据结构 题目传送门 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除 ...
- 最小生成树 & 洛谷P3366【模板】最小生成树 & 洛谷P2820 局域网
嗯... 理解生成树的概念: 在一幅图中将所有n个点连接起来的n-1条边所形成的树. 最小生成树: 边权之和最小的生成树. 最小瓶颈生成树: 对于带权图,最大权值最小的生成树. 如何操作? 1.Pri ...
随机推荐
- poj2817状态压缩 升维
/* 两两求出字符串之间最大可以匹配的值 由已知状态推导出位置状态 状态s表示已经加入到集合中的字符串,0表示串i不存在,1存在 由于字符串的加入顺序会影响结果,所以增加一维来表示 dp[S][i]表 ...
- Nginx详解三:Nginx基础篇之yum安装
Nginx快速搭建 Mainline version ----开发版:具有最新功能的版本,用于测试.研究.学习,不用于企业生成环境 Stable version----稳定版:官方认可,且通过测试的 ...
- Spring Boot如何使用Runner实现启动时调用?用法和原理都在这里
在日常的项目开发中经常会遇到这样的需求:项目启动的时候进行一些一次性的初始化工作,如读取加载资源文件.或者执行其它外部程序. 这个时候我们就可以用到spring-boot为我们提供的一种扩展机制--R ...
- 爬虫(猫眼电影+校花网+github+今日头条+拉钩)
Requests+正则表达式爬取猫眼TOP100榜电影信息 MARK:将信息写入文件解决乱码方法,开启进程池秒爬. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- 数组练习题A财务管理
第一次看全英文的题,还是有点不舒服的感觉,还是用了翻译器 Larry graduated this year and finally has a job. He's making a lot of m ...
- Ubuntu下Gradle环境配置
sudo gedit ~/.profile sudo source ~/.profile env # for java export JAVA_HOME=/home/cmm/jdk export CL ...
- MyBatis-Plus工具快速入门
MyBatis-Plus官方文档:http://mp.baomidou.com/#/quick-starthttp://mp.baomidou.com/guide/#%E7%89%B9%E6%80%A ...
- sql select中加入常量列
string sql="select a,b,'常量' as c from table" 注:单引号' ' 很重要,否则编译时会把其看成查询参数,从而提示参数未指定错误
- 006 numpy常用函数
属于Numpy的函数. 一:通用函数 1.说明 是一种对ndarray中的数据执行元素级运算的函数. 2.一元函数 3.二元函数 二:矢量计算 1.numpy.where 主要有两种用法 np.whe ...
- node 简单的爬虫
基于express爬虫, 1,node做爬虫的优势 首先说一下node做爬虫的优势 第一个就是他的驱动语言是JavaScript.JavaScript在nodejs诞生之前是运行在浏览器上的脚本语言, ...