zoukankan      html  css  js  c++  java
  • [BZOJ3796]Mushroom追妹纸:后缀自动机+KMP

    分析

    这道题有个(O(n))的后缀自动机做法,感觉很好理解就在这说一下。

    先对(s1)(s2)求最长公共子串,对于(s2)的每一个下标(i),求一个(f[i])表示以(s2[i])结尾的最长匹配长度。

    KMP求出(s3)(s2)上的所有结束位置,然后扫一遍(s2)统计答案,很简单。

    代码

    #include <bits/stdc++.h>
    #define rin(i,a,b) for(register int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(register int i=(a);i>=(b);--i)
    #define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
    typedef long long LL;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int MAXN=50005;
    int len1,len2,len3,las,tot,maxlen[MAXN],nxt[MAXN];
    char s1[MAXN],s2[MAXN],s3[MAXN];
    bool mat[MAXN];
    struct sam{
    	int fa,to[26];
    	int len;
    }a[MAXN<<1];
    
    void extend(int c){
    	int p=las,np=++tot;las=np,a[np].len=a[p].len+1;
    	while(p&&!a[p].to[c]) a[p].to[c]=np,p=a[p].fa;
    	if(!p){a[np].fa=1;return;}
    	int q=a[p].to[c];
    	if(a[p].len+1==a[q].len){a[np].fa=q;return;}
    	int nq=++tot;a[nq]=a[q],a[nq].len=a[p].len+1,a[np].fa=a[q].fa=nq;
    	while(p&&a[p].to[c]==q) a[p].to[c]=nq,p=a[p].fa;
    }
    
    void kmp(){
    	nxt[1]=0;
    	for(register int i=2,j=0;i<=len3;++i){
    		while(j&&s3[i]!=s3[j+1]) j=nxt[j];
    		if(s3[i]==s3[j+1]) ++j;
    		nxt[i]=j;
    	}
    	for(register int i=1,j=0;i<=len2;++i){
    		while(j&&s2[i]!=s3[j+1]) j=nxt[j];
    		if(s2[i]==s3[j+1]) ++j;
    		if(j==len3){
    			mat[i]=true;
    			j=nxt[j];
    		}
    	}
    }
    
    void solve(){
    	int now=1,cur=0;
    	rin(i,1,len2){
    		while(now&&!a[now].to[s2[i]-'a']) now=a[now].fa,cur=a[now].len;
    		if(!now){now=1,cur=0;continue;}
    		now=a[now].to[s2[i]-'a'],++cur;
    		maxlen[i]=cur;
    	}
    }
    
    int main(){
    	scanf("%s",s1+1);
    	getchar();
    	scanf("%s",s2+1);
    	getchar();
    	scanf("%s",s3+1);
    	len1=strlen(s1+1);
    	len2=strlen(s2+1);
    	len3=strlen(s3+1);
    	las=tot=1;
    	rin(i,1,len1) extend(s1[i]-'a');
    	kmp();
    	solve();
    	int ans=0,lim=1e9;
    	rin(i,1,len2){
    		if(mat[i]) lim=len3-1;
    		ans=std::max(ans,std::min(maxlen[i],lim++));
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    csp 初赛 (不懂的地方)
    4月11日晚科目一练习(95分)
    在博客园利用 MathJax 建支持 $\LaTeX$ 的博客
    4月9日科目一练习(88分)
    阿狸的故事
    4月10日晚科目一练习(95分)
    复变函数自身运动的三个节点
    4月11日科目一练习(97分)
    4月10日科目一练习(92分)
    极限题(4.5)
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10255768.html
Copyright © 2011-2022 走看看