版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/83894298
正题
这题也是非常的水。
先把模式串和文本串都插进字典树中。
特殊的,给文本串经过的每一个位置都加1。
最后,建一次fail指针,然后一个节点的答案就是所有fail指针间接或直接指向它的权值和。
这个东西把fail指针的队列反过来跑一遍就可以了。
因为一个节点的权值已经被后面的点更新完了。
记录一下每一个模式串的结尾节点,比较那个节点答案即可。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n;
struct node{
int t,son[26],fail;
}s[2000010];
int tot=0;
char c[160][80];
char ch[1000010];
int id[1000010];
int list[2000010];
int insert(int op){
int x=0,l=strlen(ch+1);
for(int i=1;i<=l;i++){
int temp=ch[i]-'a';
if(s[x].son[temp]==-1){
s[x].son[temp]=++tot;
memset(s[tot].son,-1,sizeof(s[tot].son));s[tot].t=0;s[tot].fail=0;
}
x=s[x].son[temp];
s[x].t+=op;
}
return x;
}
void get_fail(){
int st=1,ed=2;
list[st]=0;
while(st<ed){
int x=list[st];st++;
for(int i=0;i<26;i++){
int y=s[x].son[i];
if(y==-1) continue;
int op=s[x].fail;
while(op!=0 && s[op].son[i]==-1) op=s[op].fail;
if(x!=0 && s[op].son[i]!=-1) s[y].fail=s[op].son[i];
list[ed++]=y;
}
}
for(int i=ed-1;i>=1;i--) s[s[list[i]].fail].t+=s[list[i]].t;
}
int main(){
while(1){
scanf("%d",&n);
if(n==0) break;
tot=0;memset(s[0].son,-1,sizeof(s[0].son));
for(int i=1;i<=n;i++) scanf("%s",ch+1),strcpy(c[i]+1,ch+1),id[i]=insert(0);
scanf("%s",ch+1);insert(1);
get_fail();
int mmax=0;
for(int i=1;i<=n;i++) mmax=max(mmax,s[id[i]].t);
printf("%d\n",mmax);
for(int i=1;i<=n;i++) if(s[id[i]].t==mmax) printf("%s\n",c[i]+1);
}
}