思路

这题可以同时作为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自动机(二次加强版)的更多相关文章

  1. luoguP3796[模板]AC自动机(加强版)

    传送门 ac自动机模板,可能我写的ac自动机是有点问题的,所以跑的有些慢 暴力跳fail统计 代码: #include<cstdio> #include<iostream> # ...

  2. 【模版 Luogu P3808/P3796/P5357】AC自动机(简论)

    浙江集训Day9,没有出任何实质性成果,只好把昨天打完的板子记一下. 该博客基于luogu的三道模版题.只有一个大致的讲解,主要提供代码给自己参考. ------------------------- ...

  3. luoguP3808[模板]AC自动机(简单版)

    传送门 ac自动机模板题,裸的多串匹配 代码: #include<cstdio> #include<iostream> #include<algorithm> #i ...

  4. UVA 11019 Matrix Matcher ( 二维字符串匹配, AC自动机 || 二维Hash )

    题目: 传送门 题意: 给你一个 n * m 的文本串 T, 再给你一个 r * c 的模式串 S: 问模式串 S 在文本串 T 中出现了多少次. 解: 法一: AC自动机 (正解) 670ms 把模 ...

  5. 算法模板——AC自动机

    实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...

  6. 模板 AC自动机

    题目描述 有$N$ 个由小写字母组成的模式串以及一个文本串$T$ .每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串$T$ 中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据 ...

  7. pku1204 Word Puzzles AC自动机 二维字符串矩阵8个方向找模式串的起点坐标以及方向 挺好的!

    /** 题目:pku1204 Word Puzzles 链接:http://poj.org/problem?id=1204 题意:给定一个L C(C <= 1000, L <= 1000) ...

  8. 算法竞赛模板 AC自动机

    AC自动机基本操作 (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针. (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思 ...

  9. UVa 11019 (AC自动机 二维模式串匹配) Matrix Matcher

    就向书上说得那样,如果模式串P的第i行出现在文本串T的第r行第c列,则cnt[r-i][c]++; 还有个很棘手的问题就是模式串中可能会有相同的串,所以用repr[i]来记录第i个模式串P[i]第一次 ...

  10. AC自动机(二维) UVA 11019 Matrix Matcher

    题目传送门 题意:训练指南P218 分析:一行一行的插入,一行一行的匹配,当匹配成功时将对应子矩阵的左上角位置cnt[r][c]++;然后统计 cnt[r][c] == x 的数量 #include ...

随机推荐

  1. 最新 米哈游java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.米哈游等10家互联网公司的校招Offer,因为某些自身原因最终选择了米哈游.6.7月主要是做系统复习.项目复盘.LeetCo ...

  2. 利用elasticsearch-dump实现es索引数据迁移附脚本

    1.安装环境 CentOS Linux release 7.5.1804 (Core) 1 2.安装nodejs yum install -y nodejs 1 3.验证nodejs [root@lo ...

  3. 使用dockerfile 搭建django系统(nginx+redis+mongodb+celery)

    背景 有需求需要对django系统进行docker化,以达到灵活部署和容灾.该系统基于django 2.2版本开发,数据库采用mongodb,服务器使用nginx,因系统有部分异步任务,异步任务则采用 ...

  4. LeetCode 第 167 场周赛

    1290.二进制链表转整数 1291.顺次数 1292.元素和小于等于阈值的正方形的最大边长 1293.网格中的最短路径 1290.二进制链表转整数 1290.二进制链表转整数 给你一个单链表的引用结 ...

  5. # Ubuntu子系统安装配置

    目录 Ubuntu子系统安装配置 安装配置 终端美化 卸载 和win10之间的交互 Ubuntu子系统安装配置 亲测启动速度毫秒之间 安装配置 系统升级到一周年正式版及以上(1607) 依次在 设置 ...

  6. [python]近日 用3种库 实现简单的窗口 的回顾~

    最近任务:利用python 实现以下4个窗口弹窗. 信息提示框 文本输入框(需在窗口消失后,返回 用户输入的值) 文件选择(需在窗口消失后, 返回 用户选择的文件名的全路径) 文件夹选择(需在窗口消失 ...

  7. Delphi cxpagecontrol融合窗体

    功能说明: 一.在需要融合的每个窗体加一句 initialization RegisterClasses([TFrmDataDict]); //类名 二.cxpagecontrol融合窗体,在调用时 ...

  8. Java 抽象类详解

    在<Java中的抽象方法和接口>中,介绍了抽象方法与接口,以及做了简单的比较. 这里我想详细探讨下抽象类. 一.抽象类的定义 被关键字“abstract”修饰的类,为抽象类.(而且,abx ...

  9. Antd组件库,利用Menu组件模拟一个简单Tree组件

    当前工作中,前端的主要技术栈用是vue. 那React怎么办呢?总不至于把他扔在墙角吧! 只能在一些很小的项目上,也只有自己一个前端的时候,悄悄的上React. 当然,React项目UI组件还是最喜欢 ...

  10. Linux与Windows的设备驱动模型对比

    Linux与Windows的设备驱动模型对比 名词缩写: API 应用程序接口(Application Program Interface ) ABI 应用系统二进制接口(Application Bi ...