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 ...
随机推荐
- Java 中 try、catch、finally 语句块的执行顺序
假设代码顺序书写如下:try → catch → finally → 其他代码 则: 1.正常执行顺序:try → catch → finally → 其他代码 2.try,catch和finally ...
- Node async 控制代码执行顺序
当你有一个集合,你想循环集合,然后对每个集合按照顺序执行相应的方法你可以使用forEachSeries
- vue操作数组时遇到的坑
用vue操作数组时,一般就那几个方法,而且是可以渲染的,但是有时候列表是渲染不了的先说下操作数组的几个方法吧 1 push ( ) 这个方法是在数组的最后面添加元素 用法: 括号里写需要加入的元素 ...
- tabs 导航 及内容切换
<!-- 导航头 --> <div class="col-md-6" style="padding: 0px"> <ul id=& ...
- 关于使用pietty或putty终端连接ubuntu虚拟机时报被拒绝连接问题
首先如果要使用终端进行远程连接的ubuntu虚拟机的话,必须保证其虚拟机ip能在window下ping的动.具体的ubuntu网络配置这里不再讲,我这里使用的是NAT连接. 然后检查ssh服务是否有安 ...
- 如何判断你的windows系统是32位还是64位?
[学习笔记] 如 何判断你的windows系统是32位还是64位? java -version时,如果没有64就是32位的.eclipse.ini中如果没有64,就是32位的.但是我们的ini文件里面 ...
- Python Des加密与解密实现软件注册码、机器码
原理 判断路径下是否存在识别文件,若存在就解密对比,若不存在就进入机器码注册: 获取系统C盘序列号作为识别ID,并添加随机数作为混淆,生成最终机器码. 将机器码发给软件开发者,开发者将机器码解密后,添 ...
- 【数据结构】P1449 后缀表达式
[题目链接] https://www.luogu.org/problem/P1449 [题目描述] 所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符 ...
- k8s之dashboard认证、资源需求、资源限制及HeapSter
1.部署dashboard kubernetes-dashboard运行时需要有sa账号提供权限 Dashboard官方地址:https://github.com/kubernetes/dashboa ...
- poj 1753高斯
和前面的开关问题差不多,就是要理解一下我们方程等号的右端代表的含义是什么.我们建立的方程是想让对位的位置变或者不变,然后生成增广矩阵的时候要多注意一点. ac代码: #include #include ...