[模板][P3796]AC自动机(加强版)

Description:

输出有哪些模式串在文本串中出现次数最多,这个次数是多少

Hint:

多组数据,$ len_{文本串}<=10^6,\sum len_{模式串} <= 70*150 $

Solution:

模板题,详见代码

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int mxn=2e6+5;
char p[160][80],str[mxn];
int n,st[mxn],vis[mxn],ans[mxn];
queue<int > q;


namespace Trie {
    int mx,tot,cnt,fail[mxn],col[mxn],t[mxn][26];
    void clear(int x) {
        for(int i=0;i<26;++i) t[x][i]=0;
        fail[x]=col[x]=0;
    }
    void ins(char *s,int id) {
        int len=strlen(s),u=0;
        for(int i=0;i<len;++i) {
            if(!t[u][s[i]-'a']) t[u][s[i]-'a']=++tot,clear(tot);
            u=t[u][s[i]-'a'];
        }
        col[u]=id;
    }
    void build() {
        for(int i=0;i<26;++i) 
            if(t[0][i]) fail[t[0][i]]=0,q.push(t[0][i]);
        while(!q.empty()) {
            int u=q.front(); q.pop();
            for(int i=0;i<26;++i) {
                if(t[u][i]) fail[t[u][i]]=t[fail[u]][i],q.push(t[u][i]);
                else t[u][i]=t[fail[u]][i];
            }
        }   
    }
    int query(char *s) {
        int len=strlen(s),u=0;
        for(int i=0;i<len;++i) {
            u=t[u][s[i]-'a'];
            for(int v=u;v;v=fail[v]) {
                if(col[v]!=0)
                    ++ans[col[v]];
                if(ans[col[v]]>mx) cnt=0,mx=ans[col[v]];
                if(ans[col[v]]==mx) st[++cnt]=col[v];
            }
        }
        return mx;
    }
}
using namespace Trie;

int main()
{
    while(1) {
        clear(0);
        for(int i=1;i<=tot;++i) fail[i]=ans[i]=st[i]=col[i]=0;
        mx=0,cnt=0,tot=0;
        scanf("%d",&n); 
        if(n==0) break;
        for(int i=1;i<=n;++i) scanf("%s",p[i]);
        scanf("%s",str);
        for(int i=1;i<=n;++i) 
            ins(p[i],i); build();
        printf("%d\n",query(str));
        sort(st+1,st+cnt+1);
        for(int i=1;i<=cnt;++i) 
            cout<<p[st[i]]<<endl;
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/list1/p/10386227.html