(模板)AC自动机(加强版)
题目描述
有(N)个由小写字母组成的模式串以及一个文本串(T)。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串(T)中出现的次数最多。
输入格式
输入含多组数据。
每组数据的第一行为一个正整数(N),表示共有(N)个模式串,(1 leq N leq 150)。
接下去(N)行,每行一个长度小于等于(70)的模式串。下一行是一个长度小于等于(10^6)的文本串(T)。
输入结束标志为(N=0)。
输出格式
对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。
样例输入
2 aba bab ababababac 6 beta alpha haha delta dede tata dedeltalphahahahototatalpha 0
样例输出
4 aba 2 alpha haha
题解
这是一道AC自动机板题,
我们用普通的AC自动机直接做就好了,但是因为这道题要求求出每个模式串在文本串中出现的次数,所以我们还要对字典树上的每个节点记录每个从根到这个节点的模式串是哪一个,在这里我是用(vector)存储的。
注意:因为有多组数据,所以要注意数据的清空,不要让上一组数据影响到下一组数据
上代码:
#include<bits/stdc++.h>
#include<vector>
using namespace std;
int n;
char c[209][79],cc[1000009];
int ss[209];
struct aa{
int s;
int up;
int to[30];
vector<int>tt;
}p[100009];
int len;
int ans;
void add(int x){
int l=strlen(c[x]);
int u=0;
for(int j=0;j<l;j++){
if(p[u].to[c[x][j]-'a']) u=p[u].to[c[x][j]-'a'];
else {p[u].to[c[x][j]-'a']=++len;u=len;p[len].s=p[len].up=0;memset(p[len].to,0,sizeof(p[len].to));p[len].tt.clear();}
}
p[u].s++;
p[u].tt.push_back(x);
}
int q[1000009],l=1,r=0;
void bfs(){
for(int j=0;j<='z'-'a';j++)
if(p[0].to[j]) q[++r]=p[0].to[j];
while(l<=r){
int u=q[l++];
for(int j=0;j<='z'-'a';j++){
if(p[u].to[j]){
p[p[u].to[j]].up=p[p[u].up].to[j];
q[++r]=p[u].to[j];
}else p[u].to[j]=p[p[u].up].to[j];
}
}
}
int main(){
scanf("%d",&n);
while(n!=0){
memset(ss,0,sizeof(ss));
len=0;
p[0].s=p[0].up=0;memset(p[0].to,0,sizeof(p[0].to));p[0].tt.clear();
for(int j=1;j<=n;j++){
scanf("%s",c[j]);
add(j);
}
bfs();
scanf("%s",cc);
int l=strlen(cc);
int uu=0;
for(int j=0;j<l;j++){
uu=p[uu].to[cc[j]-'a'];
int k=uu;
while(k){
for(int j=0;j<p[k].tt.size();j++)
ss[p[k].tt[j]]++;
k=p[k].up;
}
}
int mx=0;
for(int j=1;j<=n;j++)
mx=max(mx,ss[j]);
printf("%d
",mx);
for(int j=1;j<=n;j++)
if(ss[j]==mx) printf("%s
",c[j]);
scanf("%d",&n);
}
return 0;
}