• SPOJ1812 Longest Common Substring II


    Longest Common Substring II

    给定n个串,求它们的最长公共子串。

    at most 10 lines,no more than 100000

    iwt的题解

    本题容易看出就是分别将所有串的所有匹配长度记录在状态上,然后取所有串记录值的min,后再对所有状态取max。

    但是不要忘记了一点:更新parent树的祖先。

    为什么呢?首先如果子树被匹配过了,那么长度一定大于任意祖先匹配的长度(甚至有些祖先匹配长度为0!为什么呢,因为我们在匹配的过程中,只是找到一个子串,可能还遗漏了祖先没有匹配到,这样导致了祖先的记录值为0,那么在对对应状态取min的时候会取到0,这样就wa了。而且注意,如果匹配到了当前节点,那么祖先们一定都可以赋值为祖先的length!因为当前节点的length大于任意祖先。(

    比如数据

    acbbc
    bc
    ac

    答案应该是1没错吧。如果没有更新祖先,那么答案会成0。

    这个多想想就行了。

    所以以后记住:对任意多串匹配时,凡是对同一个状态取值时,要注意当前状态的子树是否比当前状态记录的值优。

    时间复杂度:线性。

    co int N=2e5;
    namespace SAM
    {
    	int tot,last;
    	int ch[N][26],fail[N]={-1},len[N];
    	void extend(int k)
    	{
    		int cur=++tot;
    		len[cur]=len[last]+1;
    		int p=last;
    		while(~p&&!ch[p][k])
    		{
    			ch[p][k]=cur;
    			p=fail[p];
    		}
    		if(p==-1)
    			fail[cur]=0;
    		else
    		{
    			int q=ch[p][k];
    			if(len[q]==len[p]+1)
    				fail[cur]=q;
    			else
    			{
    				int clone=++tot;
    				std::copy(ch[q],ch[q]+26,ch[clone]);
    				fail[clone]=fail[q],len[clone]=len[p]+1;
    				while(~p&&ch[p][k]==q)
    				{
    					ch[p][k]=clone;
    					p=fail[p];
    				}
    				fail[cur]=fail[q]=clone;
    			}
    		}
    		last=cur;
    	}
    	int c[N],id[N],mx[N],arr[N];
    	void build(char s[],int n)
    	{
    		for(int i=0;i<n;++i)
    			extend(s[i]-'a');
    		for(int i=0;i<=tot;++i)
    			++c[len[i]];
    		for(int i=1;i<=n;++i)
    			c[i]+=c[i-1];
    		for(int i=0;i<=tot;++i)
    			id[--c[len[i]]]=i; // edit 1:--c for 0
    		std::copy(len,len+tot+1,mx);
    	}
    	void find(char s[],int n)
    	{
    		int p=0,l=0;
    		for(int i=0;i<n;++i)
    		{
    			int k=s[i]-'a';
    			if(ch[p][k])
    				p=ch[p][k],++l;
    			else
    			{
    				while(~p&&!ch[p][k])
    					p=fail[p];
    				if(p==-1)
    					p=l=0;
    				else
    					l=len[p]+1,p=ch[p][k];
    			}
    			arr[p]=std::max(arr[p],l);
    		}
    		for(int i=tot;i>=0;--i)
    		{
    			int p=id[i];
    			mx[p]=std::min(mx[p],arr[p]);
    			if(arr[p]&&fail[p])
    				arr[fail[p]]=len[fail[p]];
    			arr[p]=0;
    		}
    	}
    	int getans()
    	{
    		int ans=0;
    		for(int i=0;i<=tot;++i)
    			ans=std::max(ans,mx[i]);
    		return ans;
    	}
    }
    char buf[N];
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	scanf("%s",buf);
    	SAM::build(buf,strlen(buf));
    	while(~scanf("%s",buf))
    		SAM::find(buf,strlen(buf));
    	printf("%d
    ",SAM::getans());
    	return 0;
    }
    
  • 相关阅读:
    高职院校对口单招信息一类《专业技能》模拟试题(程序设计题)
    巧妙入侵家庭内网环境
    冰点还原忘记密码如何修改配置或卸载
    Windows 如何完整备份驱动
    如何创建自解压格式的压缩包 [ 每周小技巧 12月27日 ]
    CVE-2018-15982漏洞复现
    《内网下的自我修养》--- 基于交换机的常见攻击方式
    SQL基本注入演示
    Weblogic wls-wsat组件反序列化漏洞(CVE-2017-10271)
    通过Jenkins进行提权的一个思路
  • 原文地址:https://www.cnblogs.com/autoint/p/10347245.html
Copyright © 2020-2023  润新知