• 【题解】P3796【模板】AC自动机(加强版)


    【题解】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;
    }
    
    
  • 相关阅读:
    Javascript、Jquery获取浏览器和屏幕各种高度宽度
    使用jquery修改css中带有!important的样式属性
    jQuery事件之on()方法绑定多个选择器,多个事件
    JS 实现类似打印的效果(一个字一个字显示)
    编写jQuery 插件
    HTML5中新增加Input 的种类
    巧用Ajax的beforeSend提高用户体验
    window窗口操作
    CIDR
    mysql
  • 原文地址:https://www.cnblogs.com/winlere/p/10356911.html
Copyright © 2020-2023  润新知