1. 程式人生 > >【題解】P3796【模板】AC自動機(加強版)

【題解】P3796【模板】AC自動機(加強版)

tps mat turn 另一個 lin esp max pac org

【題解】P3796 【模板】AC自動機(加強版)

記錄當前\(cnt\)是第幾個"星"。記錄第幾個串是對應著第幾個星。

這裏補充一點對於\(AC\)自動機的理解。可能一直有個問題我沒有想明白,就是打標記的點只有一個,然而匹配時,假若一個分支包括了另一個不同的分支該怎麽辦。實際上,我們可以在匹配的時候使用\(fail\)數組進行類似鏈式前向星的遍歷,從而遍歷到那個打標記的地方。那麽問題來了,怎麽保證鏈式前向星會遍歷到那個打了標記的節點呢?答案就在\(gen\_fail\)的玄機裏。\(gen\_fail\)時,由於是找和已經匹配部分相同的後綴,所以指向的節點它到\(0\)的長度會越來越小。顯然那個有標記點的串是相較其它包括它自己的串中最短的,那麽一定會被這個鏈式前向星遍歷到。

上代碼

#include<bits/stdc++.h>

using namespace std;
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;++t)
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define ERP(t,a) for(register int t=head[a];t;t=e[t].nx)
#define Max(a,b) ((a)<(b)?(b):(a))
#define Min(a,b) ((a)<(b)?(a):(b))
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >

TMP inline ccf qr(ccf b){
    char c=getchar();
    int q=1;
    ccf x=0;
    while(c<48||c>57)
    q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)
    x=x*10+c-48,c=getchar();
    return q==-1?-x:x;
}
const int maxn=155;
struct AC{
    int fail;
    int son[27];
    int cnt;
    inline int& operator [](int x){
    return son[x];
    }
    inline int& operator [](char x){
    return son[x-‘a‘+1];
    }
}ac[maxn*70];

string x[maxn];
int toac[maxn];
int acnt[maxn];
int macnt[maxn];
int act;
int prcnt;
int n;

inline int build(string p,int len){
    register int now=0;
    RP(t,0,len-1){
    if(!ac[now][p[t]])
        ac[now][p[t]]=++act;
    now=ac[now][p[t]];
    }
    if(!ac[now].cnt)
    ac[now].cnt=++prcnt;
    return ac[now].cnt;
}

queue < int > q;
inline void gen(){
    RP(t,1,26){
    if(ac[0][t])
        q.push(ac[0][t]);
    }
    while(!q.empty()){
    register int now=q.front();
    q.pop();
    RP(t,1,26){
        if(ac[now][t])
        ac[ac[now][t]].fail=ac[ac[now].fail][t],q.push(ac[now][t]);
        else
        ac[now][t]=ac[ac[now].fail][t];
    }
    }
}

inline void match(string p,int len){
    register int now=0;
    RP(t,0,len-1){
    now=ac[now][p[t]];
    for(register int i=now;i;i=ac[i].fail){
        if(ac[i].cnt)
        macnt[ac[i].cnt]++;
    }
    }
}
    


int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    while(  (n=qr(1))  ){
    memset(ac,0,sizeof ac);
    memset(macnt,0,sizeof macnt);
    act=prcnt=0;
    RP(t,1,n){
        cin>>x[t];
        toac[t]=build(x[t],x[t].length());
    }
    gen();
    cin>>x[0];
    match(x[0],x[0].length());
    register int ans=0;
    RP(t,1,prcnt)
        ans=Max(ans,macnt[t]);
    cout<<ans<<endl;
    RP(t,1,n)
        if(macnt[toac[t]]==ans)
        cout<<x[t]<<endl;
    }
    return 0;
}

【題解】P3796【模板】AC自動機(加強版)