P5357 【模板】AC自动机(二次加强版)
思路
这题可以同时作为AC自动机和SAM的模板啊喂
AC自动机
对T建出AC自动机,把S在上面匹配,然后记录每个点被经过的次数,最后统计一次即可(暴力跳fail的复杂度是不对的)
SAM
对S建出SAM,然后每次把T在上面匹配,如果匹配长度等于T的长度,输出出现次数,否则输出0
但是卡了SAM的空间
代码
AC自动机
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int trans[200200][26],fail[200200],ends[200200],cnt[200200],Nodecnt=0,root=0,n;
char s[2000200];
void insert(char *s,int len,int inq){
int p=root;
for(int i=0;i<len;i++){
if(!trans[p][s[i]-'a'])
trans[p][s[i]-'a']=++Nodecnt;
p=trans[p][s[i]-'a'];
}
ends[inq]=p;
}
queue<int> q;
void get_AC(void){
for(int i=0;i<26;i++)
if(trans[root][i]){
fail[trans[root][i]]=root;
q.push(trans[root][i]);
}
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<26;i++){
if(trans[x][i]){
fail[trans[x][i]]=trans[fail[x]][i];
q.push(trans[x][i]);
}
else
trans[x][i]=trans[fail[x]][i];
}
}
}
int in[2000200];
void topu(void){
for(int i=1;i<=Nodecnt;i++)
in[fail[i]]++;
for(int i=1;i<=Nodecnt;i++)
if(!in[i])
q.push(i);
while(!q.empty()){
int x=q.front();
q.pop();
cnt[fail[x]]+=cnt[x];
in[fail[x]]--;
if(!in[fail[x]])
q.push(fail[x]);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
insert(s,strlen(s),i);
}
get_AC();
scanf("%s",s);
int lent=strlen(s),p=root;
for(int i=0;i<lent;i++){
p=trans[p][s[i]-'a'];
cnt[p]++;
}
topu();
for(int i=1;i<=n;i++){
printf("%d\n",cnt[ends[i]]);
}
return 0;
}
SAM
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
#include <queue>
using namespace std;
int maxlen[1001000*2],trans[1001000*2][26],suflink[1001000*2],n,Nodecnt=1,len,endpos[1001000*2];
char S[1001000];
string T[200100];
int New_state(int _maxlen,int *_trans,int _suflink){
++Nodecnt;
maxlen[Nodecnt]=_maxlen;
if(_trans)
for(int i=0;i<26;i++)
trans[Nodecnt][i]=_trans[i];
suflink[Nodecnt]=_suflink;
return Nodecnt;
}
int add_len(int u,int c){
int z=New_state(maxlen[u]+1,NULL,0);
endpos[z]=1;
while(u&&trans[u][c]==0){
trans[u][c]=z;
u=suflink[u];
}
if(!u){
suflink[z]=1;
return z;
}
int v=trans[u][c];
if(maxlen[v]==maxlen[u]+1){
suflink[z]=v;
return z;
}
int y=New_state(maxlen[u]+1,trans[v],suflink[v]);
suflink[z]=suflink[v]=y;
while(u&&trans[u][c]==v){
trans[u][c]=y;
u=suflink[u];
}
return z;
}
int ranks[1001000*2],barrel[1001000*2];
void c_sort(int n,int lim){
memset(barrel,0,sizeof(barrel));
for(int i=1;i<=Nodecnt;i++)
barrel[maxlen[i]]++;
for(int i=1;i<=lim;i++)
barrel[i]+=barrel[i-1];
for(int i=1;i<=Nodecnt;i++)
ranks[barrel[maxlen[i]]--]=i;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
cin>>T[i];
scanf("%s",S+1);
len=strlen(S+1);
int last=1;
for(int i=1;i<=len;i++)
last=add_len(last,S[i]-'a');
c_sort(Nodecnt,len);
for(int i=Nodecnt;i>=1;i--)
endpos[suflink[ranks[i]]]+=endpos[ranks[i]];
for(int i=1;i<=n;i++){
int lent=T[i].length();
int nowp=1,matchlen=0;
for(int j=0;j<lent;j++){
if(trans[nowp][T[i][j]-'a']){
matchlen++;
nowp=trans[nowp][T[i][j]-'a'];
}
else{
while(nowp&&trans[nowp][T[i][j]-'a']==0)
nowp=suflink[nowp];
if(!nowp){
nowp=1;
matchlen=0;
}
else{
matchlen=maxlen[nowp]+1;
nowp=trans[nowp][T[i][j]-'a'];
}
}
}
if(matchlen==lent){
// int ans=0;
// while(nowp){
// ans+=endpos[nowp];
// nowp=suflink[nowp];
// }
printf("%d\n",endpos[nowp]);
}
else{
printf("0\n");
}
}
return 0;
}
P5357 【模板】AC自动机(二次加强版)的更多相关文章
- luoguP3796[模板]AC自动机(加强版)
传送门 ac自动机模板,可能我写的ac自动机是有点问题的,所以跑的有些慢 暴力跳fail统计 代码: #include<cstdio> #include<iostream> # ...
- 【模版 Luogu P3808/P3796/P5357】AC自动机(简论)
浙江集训Day9,没有出任何实质性成果,只好把昨天打完的板子记一下. 该博客基于luogu的三道模版题.只有一个大致的讲解,主要提供代码给自己参考. ------------------------- ...
- luoguP3808[模板]AC自动机(简单版)
传送门 ac自动机模板题,裸的多串匹配 代码: #include<cstdio> #include<iostream> #include<algorithm> #i ...
- UVA 11019 Matrix Matcher ( 二维字符串匹配, AC自动机 || 二维Hash )
题目: 传送门 题意: 给你一个 n * m 的文本串 T, 再给你一个 r * c 的模式串 S: 问模式串 S 在文本串 T 中出现了多少次. 解: 法一: AC自动机 (正解) 670ms 把模 ...
- 算法模板——AC自动机
实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...
- 模板 AC自动机
题目描述 有$N$ 个由小写字母组成的模式串以及一个文本串$T$ .每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串$T$ 中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据 ...
- pku1204 Word Puzzles AC自动机 二维字符串矩阵8个方向找模式串的起点坐标以及方向 挺好的!
/** 题目:pku1204 Word Puzzles 链接:http://poj.org/problem?id=1204 题意:给定一个L C(C <= 1000, L <= 1000) ...
- 算法竞赛模板 AC自动机
AC自动机基本操作 (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针. (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思 ...
- UVa 11019 (AC自动机 二维模式串匹配) Matrix Matcher
就向书上说得那样,如果模式串P的第i行出现在文本串T的第r行第c列,则cnt[r-i][c]++; 还有个很棘手的问题就是模式串中可能会有相同的串,所以用repr[i]来记录第i个模式串P[i]第一次 ...
- AC自动机(二维) UVA 11019 Matrix Matcher
题目传送门 题意:训练指南P218 分析:一行一行的插入,一行一行的匹配,当匹配成功时将对应子矩阵的左上角位置cnt[r][c]++;然后统计 cnt[r][c] == x 的数量 #include ...
随机推荐
- Cron 表达式学习
1.7个子域的说明 cron 的表达式是字符串,实际上是由七子表达式(从左到右),描述个别细节的时间表.这些子表达式是分开的空白. 顺序(从左到右) 子串 有效数字 有效字符 1 Seconds(秒) ...
- VSCode插件Prettier配置
参考链接:https://blog.csdn.net/wengou3033/article/details/88749448 Prettier格式化配置
- Cent7.2单用户模式
1. 在进入系统时选择内核启动. 2. 按'e'进入编辑模式,找到带有内核的那一行. 3. 将ro(read only)改为rw init=/sysboot/bin/sh. 4. 按下ctrl+x ...
- 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用
目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...
- 注解@PostConstruct与@PreDestroy详解及实例
Java EE5 引入了@PostConstruct和@PreDestroy这两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作.此文主要说明@PostConstru ...
- thinkphp5分页查询paginate()传递参数
使用paginate()分页,我这里实现的是搜索后分页显示,翻页后传递搜索关键字 www.demo.com/home/search/?k=搜索关键字&page=2 搜索分页源码在: think ...
- spark异常篇-Removing executor 5 with no recent heartbeats: 120504 ms exceeds timeout 120000 ms 可能的解决方案
问题描述与分析 题目中的问题大致可以描述为: 由于某个 Executor 没有按时向 Driver 发送心跳,而被 Driver 判断该 Executor 已挂掉,此时 Driver 要把 该 Exe ...
- django 中静态文件项目加载问题
问题描述: django项目中创建了多个app后,每个app中都有对应的static静态文件.整个项目运行时这些静态文件的加载就是一个问题,因为整个项目我只参与了一部分,项目部署之类的并没有参与.我写 ...
- java lesson10homework
1. 输入三个整数x, y, z,请把这三个数由小到大输出. 2. package Homework10; 3. //:类方法 4. public class Sort { 5. voi ...
- T4模板生成文件要点记录
可以使用 $(variableName) 语法引用 Visual Studio 或 MSBuild 变量(如 $(SolutionDir)),以及使用 %VariableName% 来引用环境变量.介 ...