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

浅谈\(AC\)自动机:https://www.cnblogs.com/AKMer/p/10448651.html

题目传送门:https://www.luogu.org/problemnew/show/P3796

记录一下母串在\(AC\)自动机上面经过每个点的次数,然后深度较深的点用自己的次数累加在自己的\(fail\)上去,就能找出每个字符串出现的次数了。

时间复杂度:\(O(\sum len_i)\)

空间复杂度:\(O(\sum len_i)\)

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn=155,maxlen=1e6+5;

int n;
int ans[maxn];
char s[maxlen];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

struct data {
    char s[75];
    int len,node,id;
}a[maxn];

bool cmp(data a,data b) {
    return a.id<b.id;
}

struct AC_automation {
    int tot,root;
    bool bo[maxn*70];
    int son[maxn*70][26],list[maxn*70];
    int fail[maxn*70],id[maxn*70],cnt[maxn*70];

    void clear() {
        tot=root=1;
        memset(bo,0,sizeof(bo));
        memset(id,0,sizeof(id));
        memset(son,0,sizeof(son));
        memset(cnt,0,sizeof(cnt));
        memset(fail,0,sizeof(fail));
    }

    void ins(int ID) {
        int pos=root;a[ID].id=ID;
        a[ID].len=strlen(a[ID].s+1);
        for(int i=1;i<=a[ID].len;i++) {
            if(son[pos][a[ID].s[i]-'a'])
                pos=son[pos][a[ID].s[i]-'a'];
            else pos=son[pos][a[ID].s[i]-'a']=++tot;
        }
        id[pos]=ID,a[ID].node=pos;
    }

    void make_fail() {
        int h=0,t=0;
        for(int i=0;i<26;i++)
            if(!son[root][i])son[root][i]=root;
            else fail[son[root][i]]=root,list[t++]=son[root][i];
        while(h!=t) {
            int u=list[h++];
            for(int i=0;i<26;i++)
                if(son[u][i]) {
                    fail[son[u][i]]=son[fail[u]][i];
                    list[t++]=son[u][i];
                }
                else son[u][i]=son[fail[u]][i];
        }
    }

    void find() {
        int len=strlen(s+1),pos=root;
        for(int i=1;i<=len;i++)
            pos=son[pos][s[i]-'a'],cnt[pos]++;
        int res=0;
        for(int i=tot;i;i--)
            if(!bo[i]) {
                int pos=i,sum=0;
                while(pos!=root) {
                    sum+=cnt[pos];
                    if(id[pos]) {
                        res=max(res,sum);
                        ans[id[pos]]=sum;
                    }bo[pos]=1;
                    pos=fail[pos];
                }
            }
        printf("%d\n",res);
        for(int i=1;i<=n;i++)
            if(ans[i]==res)printf("%s\n",a[i].s+1);
    }
}A;

int main() {
    while(1) {
        n=read();if(!n)break;A.clear();
        for(int i=1;i<=n;i++)
            scanf("%s",a[i].s+1),A.ins(i);
        A.make_fail(),scanf("%s",s+1),A.find();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AKMer/p/10449106.html