题目大意:给你n个模板串和一个文本串,让你求出在文本串中出现长度最多的模板串,先输出最大次数,如果有多个,那么按照输入
顺序依次输出。
思路:书上的例题,AC自动机的模板题。为了去重,直接给每个字符串编号就行了。
发现还是按照书上last这样来更加好,当然也可以不要last,直接暴力+。
顺序依次输出。
思路:书上的例题,AC自动机的模板题。为了去重,直接给每个字符串编号就行了。
发现还是按照书上last这样来更加好,当然也可以不要last,直接暴力+。
代码如下:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 155;
const int MAX_LEN = 77;
char str[MAXN][MAX_LEN];
const int MAX_NODE = 11111;
const int SIGMA_SIZE = 26;
int cnt[MAX_NODE];
struct AC
{
int ch[MAX_NODE][SIGMA_SIZE];
int val[MAX_NODE];
int fail[MAX_NODE];
int last[MAX_NODE];
int tot;
AC()
{
tot = 1;
val[0] = 0;
memset(ch[0],0,sizeof(ch[0]));
}
int idx(char c)
{
return c - 'a';
}
void insert(char *s,int v)
{
int len = strlen(s);
int u = 0;
for(int i = 0;i<len;i++)
{
int c = idx(s[i]);
if(!ch[u][c])
{
val[tot] = 0;
memset(ch[tot],0,sizeof(ch[tot]));
ch[u][c] = tot++;
}
u = ch[u][c];
}
val[u] = v;
}
void get_fail()
{
queue<int> q;
fail[0] = 0;
for(int i = 0;i<SIGMA_SIZE;i++)
{
int u = ch[0][i];
if(u)
{
q.push(u);
fail[u] = 0;
last[0] = 0;
}
}
while(!q.empty())
{
int u = q.front();q.pop();
for(int i = 0;i<SIGMA_SIZE;i++)
{
int v = ch[u][i];
if(!v)
{
ch[u][i] = ch[fail[u]][i];//改造叶子节点
continue;
}
q.push(v);
int j = fail[u];
while(j && !ch[j][i])
j = fail[j];
fail[v] = ch[j][i];
last[v] = val[fail[v]] ? fail[v] : last[fail[v]];//后缀链接,指向j沿fail往回走遇到的下一个单词节点的编号
//printf("u = %d,v = %d,f = %d\n",u,v,fail[v]);
}
}
}
void find(char *s)
{
memset(cnt,0,sizeof(cnt));
int len = strlen(s);
int j = 0;
for(int i = 0;i<len;i++)
{
int c = idx(s[i]);
//while(j && !ch[j][c]) j = fail[j];改造后不需要加这句话了
j = ch[j][c];
//printf("i = %d,j = %d\n",i,j);
if(val[j]) print(j);
else if(last[j]) print(last[j]);
}
}
void print(int u)
{
if(u)
{
cnt[val[u]]++;
print(last[u]);
}
}
};
char T[1111111];
int main()
{
int n;
while(~scanf("%d",&n) && n)
{
AC ac;
for(int i = 0;i<n;i++)
{
scanf("%s",str[i]);
ac.insert(str[i],i+1);
}
scanf("%s",T);
ac.get_fail();
ac.find(T);
int maxx = -1;
for(int i = 0;i<n;i++)
maxx = max(maxx,cnt[i+1]);
printf("%d\n",maxx);
for(int i = 0;i<n;i++)
if(cnt[i+1] == maxx)
puts(str[i]);
}
return 0;
}
/*
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
2
aba
bab
ababababac
3
abcd
bcde
cd
abcd
*/
如果不要last ,直接暴力+,那么就是 find 里加这句话:
for(int k = j;k;k = fail[k])
if(val[k]) cnt[val[k]] ++;