AC(cept)自动机

题目链接:

https://www.luogu.org/problemnew/show/P3796

题目描述

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

输入输出格式

输入格式:

输入含多组数据。

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

接下去N行,每行一个长度小于等于70的模式串。下一行是一个长度小于等于10^6的文本串T。

输入结束标志为N=0。

输出格式:

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

分析:

没啥好分析的,就是板子。结构体直接多一个成员变量order,用来记录到当前结点的是第几个串,如果是0就代表没有这个串。在ac匹配的时候拿一个ans数组存一下出现次数,最后统计一下输出。完结撒花啦! 

实现代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<algorithm>
#include<cmath>
#define rg register
#define il inline
using namespace std;
typedef unsigned long long ll;
typedef unsigned long long ll;
ll read(){
    ll ans=0,flag=1;char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') flag=-1;
    ans=ch^48;
    while((ch=getchar())>='0'&&ch<='9') ans=(ans<<3)+(ans<<1)+(ch^48);
    return flag*ans;
}
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
struct trie{
    int ch[26];
    int fail;
    int ord;
}ac[12000];
int now=0;
void insertstr(int i,char *s){
    int root=0;
    while(*s){
        if(ac[root].ch[*s-'a']==0){
            ac[root].ch[*s-'a']=++now;
        }
        root=ac[root].ch[*s-'a'];
        s++;
    }
    ac[root].ord=i+1;
}
il void getfail(){
    queue<int>q;
    for(rg int i=0;i<26;i++){
        if(ac[0].ch[i]){
            ac[ac[0].ch[i]].fail=0;
            q.push(ac[0].ch[i]);
        }
    }
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(rg int i=0;i<26;i++){
            if(ac[now].ch[i]){
                ac[ac[now].ch[i]].fail=ac[ac[now].fail].ch[i];
                q.push(ac[now].ch[i]);
            }
            else
                ac[now].ch[i]=ac[ac[now].fail].ch[i];
        }
    }
}
int ans[160];
void aczdj(char *s){
    int now=0;
    while(*s){
        now=ac[now].ch[*s-'a'];
        for(int i=now;i;i=ac[i].fail){
            if(ac[i].ord)
                ans[ac[i].ord]++;
        }
        s++;
    }
}
char longbuff[1000005];
int main()
{
    char buff[160][80];
    int n;
    while(cin>>n&&n){
        memset(ac,0,sizeof ac);
        memset(ans,0,sizeof ans);
        now=0;
        for(rg int i=0;i<n;i++){
            scanf("%s",buff[i]);
            insertstr(i,buff[i]);
        }
        scanf("%s",longbuff);
        getfail();
        aczdj(longbuff);
        int m=0;
        for(rg int i=1;i<=n;i++)
            m=max(ans[i],m);
        printf("%d\n",m);
        for(rg int i=1;i<=n;i++){
            if(ans[i]==m)
                puts(buff[i-1]);
        }
        //puts("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ffscas/article/details/87306697