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

题目描述

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

输入格式

输入含多组数据。

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

接下去NN行,每行一个长度小于等于7070的模式串。下一行是一个长度小于等于10^6106的文本串TT。

输入结束标志为N=0N=0。

输出格式

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

输入输出样例

输入 

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

输出 

4
aba
2
alpha
haha

找到在母串中出现次数最多的那个子串,有多个就按照输入顺序输出,AC自动机模板的加强版

AC代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<map>
#include<iomanip>
#include<math.h>
#include<sstream>
using namespace std;
typedef long long ll;
typedef double ld;
string mob[300010];
int num[300010];
int trip[300010][26];
int fail[300010];
int ans[300010];
int temp;
int n,siz;
void add(string s,int v)
{
    int now=0;
    for(int i=0; i<s.size(); i++)
    {
        int o=s[i]-'a';
        if(!trip[now][o])
            trip[now][o]=++siz;
        now=trip[now][o];
    }
    num[now]=v;
}
void getfail()
{
    int now=0;
    queue<int>que;
    for(int i=0; i<26; i++)
        if(trip[0][i])
            que.push(trip[0][i]),fail[trip[0][i]]=0;
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=0; i<26; i++)
        {
            int v=trip[u][i];
            if(v)
            {
                fail[v]=trip[fail[u]][i];
                que.push(v);
            }
            else
                trip[u][i]=trip[fail[u]][i];
        }
    }
}
void query(string s)
{
    int now=0;
    for(int i=0; i<s.size(); i++)
    {
        now=trip[now][s[i]-'a'];
        for(int j=now; j; j=fail[j])
            ans[num[j]]++;
    }
}
int main()
{
    while(cin>>n&&n)
    {
        memset(num,0,sizeof(num));
        memset(ans,0,sizeof(ans));
        memset(trip,0,sizeof(trip));
        memset(fail,0,sizeof(fail));
        siz=0;
        for(int i=1; i<=n; i++)
        {
            cin>>mob[i];
            add(mob[i],i);
        }
        getfail();
        string k;
        cin>>k;
        query(k);
        temp=0;
        for(int i=1; i<=n; i++)
            if(ans[i]>temp)
                temp=ans[i];
        cout<<temp<<endl;
        for(int i=1; i<=n; i++)
            if(ans[i]==temp)
                cout<<mob[i]<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值