zoukankan      html  css  js  c++  java
  • SPOJ Longest Common Substring II

    题目连接:戳我

    题目大意:求n个字符串的最长公共子串。
    它的简化版——这里

    当然我们可以用SA写qwq,也可以用广义SAM写qwq
    这里介绍纯SAM的写法。。。就是对其中一个建立后缀自动机,然后剩下的N-1个往上面匹配。
    (sum[i])表示到以节点i为根的子树中,最长能够匹配到的最长的子串的长度。
    匹配和它的弱化版基本一样,就是注意每次在parent tree上要用拓扑序从下往上更新答案。
    注意每个点最大的匹配不能超过它所在类的longest

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 1000000 
    using namespace std;
    int T,k,last=1,tot=1;
    int a[MAXN],c[MAXN],ans[MAXN],sum[MAXN];
    char s[MAXN];
    struct Node{int son[26],ff,len;}t[MAXN<<1];
    inline void extend(int c)
    {
        int p=last,np=++tot;last=np;
        t[np].len=t[p].len+1;
        while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
        if(!p)t[np].ff=1;
        else
        {
            int q=t[p].son[c];
            if(t[q].len==t[p].len+1)t[np].ff=q;
            else
            {
                int nq=++tot;
                t[nq]=t[q]; 
                t[nq].len=t[p].len+1;
                t[q].ff=t[np].ff=nq;
                while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
            }
        }
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%s",s+1);
    	int len=strlen(s+1);
    	for(int i=1;i<=len;i++) extend(s[i]-'a');
    	for(int i=1;i<=tot;i++) c[t[i].len]++;
    	for(int i=1;i<=tot;i++) c[i]+=c[i-1];
    	for(int i=1;i<=tot;i++) a[c[t[i].len]--]=i;
    	for(int i=1;i<=tot;i++) ans[i]=t[i].len;
    	while(scanf("%s",s+1)!=EOF)
    	{
    		len=strlen(s+1);
    		memset(sum,0,sizeof(sum));
    		int cur_ans=0;
    		int now=1;
    		for(int i=1;i<=len;i++)
    		{
    			if(t[now].son[s[i]-'a']) cur_ans++,now=t[now].son[s[i]-'a'];
    			else
    			{
    				while(now&&!t[now].son[s[i]-'a']) now=t[now].ff;
    				if(!now) cur_ans=0,now=1;
    				else cur_ans=t[now].len+1,now=t[now].son[s[i]-'a'];
    			}
    			sum[now]=max(sum[now],cur_ans);
    		}
    		for(int i=tot;i>=1;i--)
    		{
    			int cur=a[i];
    			sum[t[cur].ff]=max(sum[t[cur].ff],min(t[t[cur].ff].len,sum[cur]));
    		}
    		for(int i=1;i<=tot;i++) ans[i]=min(ans[i],sum[i]);
    	}
    	int maxx=0;
    	for(int i=1;i<=tot;i++) maxx=max(maxx,ans[i]);
    	printf("%d
    ",maxx);
    	return 0;
    }
    
  • 相关阅读:
    在Chrome浏览器中保存的密码有多安全?
    进程上下文切换 – 残酷的性能杀手(上)
    进程上下文切换 – 残酷的性能杀手(下)
    javascript推荐书籍
    使用Visual Studio 利用WinGDB编译和远程调试嵌入式Linux的程序
    Source Insight 3.X 标签插件v1.0发布
    QQ空间自动发广告解决方法
    Java---实力弹弹球,弹弹弹
    HDOJ 2027 统计元音
    Java---计算机贷款支付额计算(用对话框实现)
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10732565.html
Copyright © 2011-2022 走看看