题目描述

有 \(N\) 个由小写字母组成的模式串以及一个文本串 \(T\) 。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串 \(T\) 中出现的次数最多。

输入输出格式

输入格式:

输入含多组数据。

每组数据的第一行为一个正整数 \(N\) ,表示共有 \(N\) 个模式串, \(1 \leq N \leq 150\) 。

接下去 \(N\) 行,每行一个长度小于等于 \(70\) 的模式串。下一行是一个长度小于等于 \(10^6\) 的文本串 \(T\) 。

输入结束标志为 \(N=0\) 。

输出格式:

对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

输入输出样例

输入样例#1:

2
aba
bab
ababababac
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
0

输出样例#1:

4
aba
2
alpha
haha

题解

同样的,简单匹配,匹配到有结尾标记的点,就把标记的点的贡献加上

最后取个最大值,找串输出就好了

因为可能存在相同的串,结尾标记用vector存就好了

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=150+10,MAXS=1000000+10,MAXM=15000+10;
int n,ch[MAXM][30],fail[MAXM],last[MAXM],ed[MAXM],ans[MAXN],cnt;
char s[MAXS],t[MAXN][80];
std::queue<int> q;
std::vector<int> V[MAXM];
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void init()
{
for(register int i=0,lt=strlen(s);i<lt;++i)s[i]-='a'-1;
}
inline void insert(int rk)
{
int x=0;
for(register int i=0,lt=strlen(s);i<lt;++i)
if(!ch[x][s[i]])x=ch[x][s[i]]=++cnt;
else x=ch[x][s[i]];
ed[x]=1;
V[x].push_back(rk);
}
inline void getfail()
{
for(register int i=1;i<=26;++i)
if(ch[0][i])q.push(ch[0][i]);
while(!q.empty())
{
int x=q.front();
q.pop();
for(register int i=1,y,z;i<=26;++i)
if(ch[x][i])
{
y=ch[x][i],z=fail[x];
while(z&&!ch[z][i])z=fail[z];
fail[y]=ch[z][i];
last[y]=ed[fail[y]]?fail[y]:last[fail[y]];
q.push(y);
}
else ch[x][i]=ch[fail[x]][i];
}
}
inline void save(int x)
{
if(x)
{
if(ed[x])
for(register int i=0,lt=V[x].size();i<lt;++i)ans[V[x][i]]++;
save(last[x]);
}
}
inline void match()
{
int x=0;
for(register int i=0,lt=strlen(s);i<lt;++i)x=ch[x][s[i]],save(ed[x]||last[x]?x:0);
}
int main()
{
while(scanf("%d",&n)!=EOF&&n)
{
for(register int i=1;i<=cnt;++i)V[i].clear();
memset(ch,0,sizeof(ch));
memset(ed,0,sizeof(ed));
memset(ans,0,sizeof(ans));
memset(fail,0,sizeof(fail));
memset(last,0,sizeof(last));
cnt=0;
for(register int i=1;i<=n;++i)
{
scanf("%s",s);
memcpy(t[i],s,sizeof(t[i]));
init();insert(i);
}
getfail();
scanf("%s",s);init();match();
int len=0;
for(register int i=1;i<=n;++i)chkmax(len,ans[i]);
write(len,'\n');
for(register int i=1;i<=n;++i)
if(ans[i]==len)puts(t[i]);
}
return 0;
}

【刷题】洛谷 P3796 【模板】AC自动机(加强版)的更多相关文章

  1. 洛谷 - P3966 - 单词 - AC自动机

    https://www.luogu.org/problemnew/show/P3966 因为文本串就是字典本身,所以这个和平时的AC自动机不太一样.平时的query要沿着fail树把子树的出现次数依次 ...

  2. 洛谷.3121.审查(AC自动机 链表)

    题目链接 //删掉一个单词需要前移一段位置,用链表维护就好了 复杂度O(sum(len)) #include <cstdio> #include <cstring> #defi ...

  3. 洛谷 - P2444 - 病毒 - AC自动机

    https://www.luogu.org/problemnew/show/P2444 有点恶心,不太明白fail的意义. #include<bits/stdc++.h> using na ...

  4. 洛谷 P3804 [模板] 后缀自动机

    题目:https://www.luogu.org/problemnew/show/P3804 模仿了一篇题解,感觉很好写啊. 代码如下: #include<cstdio> #include ...

  5. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  6. 洛谷P1120 小木棍 [数据加强版](搜索)

    洛谷P1120 小木棍 [数据加强版] 搜索+剪枝 [剪枝操作]:若某组拼接不成立,且此时 已拼接的长度为0 或 当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案时,则可直接跳出循环.因为此时继续 ...

  7. 【AC自动机】洛谷三道模板题

    [题目链接] https://www.luogu.org/problem/P3808 [题意] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. [题解] 不再介绍基础知识了,就是裸的模 ...

  8. 洛谷P3796 【模板】AC自动机(加强版)(AC自动机)

    洛谷题目传送门 先膜一发yyb巨佬 orz 想学ac自动机的话,推荐一下yyb巨佬的博客,本蒟蒻也是从那里开始学的. 思路分析 裸的AC自动机,这里就不讲了.主要是这题太卡时了,尽管时限放的很大了.. ...

  9. 洛谷P3796 - 【模板】AC自动机(加强版)

    原题链接 Description 模板题啦~ Code //[模板]AC自动机(加强版) #include <cstdio> #include <cstring> int co ...

  10. 洛谷 P3796 【模板】AC自动机(加强版)(AC自动机)

    题目链接:https://www.luogu.com.cn/problem/P3796 AC自动机:复杂度$O( (N+M)\times L )$,N为模式串个数,L为平均长度,M为文章长度. ins ...

随机推荐

  1. 求两个字符串的最长公共子串——Java实现

    要求:求两个字符串的最长公共子串,如“abcdefg”和“adefgwgeweg”的最长公共子串为“defg”(子串必须是连续的) public class Main03{ // 求解两个字符号的最长 ...

  2. localhost/127.0.0.1/本机IP的区别以及端口号

    端口号: http请求默认的端口是:80 PHPstudy中的端口号: Apache服务器的端口是:80 MySQL数据库的端口是:3306 PHP项目端口是:9000 禅道中的端口号: Apache ...

  3. oracle的分号和斜杠/

    ;是执行语句必须的/是执行语句块必须的 比如执行一个触发器 CREATE OR REPLACE TRIGGER "TRG_1" BEFORE INSERT ON "CAT ...

  4. 使用Photon引擎进行unity网络游戏开发(三)——网络游戏大厅及房间

    使用Photon引擎进行unity网络游戏开发(三)--网络游戏大厅及房间 Photon PUN Unity 网络游戏开发 连接到Photon ConnectUsingSettings 设置你的客户端 ...

  5. POJ-2018(二分)

    //意是在一个数组里,寻找一段连续和,使其平均和最大,但是长度不能小于F, //首先可以看出是满足单调性的,但是怎么二分呢, //我们先枚举一个可能的数. //然后数组里的值全部减去这个值(结果会有正 ...

  6. 433. Number of Islands【LintCode java】

    Description Given a boolean 2D matrix, 0 is represented as the sea, 1 is represented as the island. ...

  7. 完美的【去重留一】SQL

    DELETE consum_record FROM consum_record, ( SELECT min(id) id, user_id, monetary, consume_time FROM c ...

  8. 最短路径算法(I)

    弗洛伊德算法(Floyed-Warshall) 适用范围及时间复杂度 该算法的时间复杂度为O(N^3),适用于出现负边权的情况. 可以求取最短路径或判断路径是否连通.可用于求最小环,比较两点之间的大小 ...

  9. Docker 快速入门教程

    本文目的是给几乎从未接触过docker,或者仅仅是听说或者通过新闻了解过Docker的同学 通过一个已有的Docker仓库构建和提交自己的Docker 镜像 这里会涉及到一些概念,但是不单独介绍 这里 ...

  10. dp算法之硬币找零问题

    题目:硬币找零 题目介绍:现在有面值1.3.5元三种硬币无限个,问组成n元的硬币的最小数目? 分析:现在假设n=10,画出状态分布图: 硬币编号 硬币面值p 1 1 2 3 3 5 编号i/n总数j ...