zoukankan      html  css  js  c++  java
  • SPOJ LCS2

    原文链接http://www.cnblogs.com/zhouzhendong/p/8982484.html

    题目传送门 - SPOJ LCS2

    题意

      求若干$(若干<10)$个字符串的最长公共连续子串长度。

      串长$leq 100000$

    题解

      建议在做本题之前,先去做SPOJ LCS,本题是其升级版。

      题解链接 - SPOJ LCS - http://www.cnblogs.com/zhouzhendong/p/8982392.html

      对于本题,我们只需要保持一下之后每一个串在第一个串的$SAM$的每一个状态上的最大匹配长度,然后最后对于每一个状态,取$min(该状态的Max值,其他所有字符串在该状态上面的最大匹配长度的最小值)$即可。

      于是,我们先像SPOJ LCS一样,让所有串都走一遍,然后记录一下值。

      注意到,每一个状态的结果都会对其$fa$做贡献。

      于是我们可以基数排序预处理拓扑序,然后逆序更新即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=200005;
    int n,m=0,last=1,size=1,Max[15][N];
    int id[N],tax[N];
    char s[N];
    struct SAM{
    	int Next[26],fa,Max;
    }t[N];
    void expend(int c){
    	int p=last,np=++size,q,nq;
    	t[np].Max=t[p].Max+1;
    	for (;!t[p].Next[c];p=t[p].fa)
    		t[p].Next[c]=np;
    	q=t[p].Next[c];
    	if (t[q].Max==t[p].Max+1)
    		t[np].fa=q;
    	else {
    		nq=++size;
    		t[nq]=t[q],t[nq].Max=t[p].Max+1;
    		t[q].fa=t[np].fa=nq;
    		for (;t[p].Next[c]==q;p=t[p].fa)
    			t[p].Next[c]=nq;
    	}
    	last=np;
    }
    int main(){
    	t[0].Max=-1;
    	for (int i=0;i<26;i++)
    		t[0].Next[i]=1;
    	gets(s);
    	n=strlen(s);
    	for (int i=0;i<n;i++)
    		expend(s[i]-'a');
    	for (int i=1;i<=size;i++)
    		tax[t[i].Max]++;
    	for (int i=1;i<=size;i++)
    		tax[i]+=tax[i-1];
    	for (int i=1;i<=size;i++)
    		id[tax[t[i].Max]--]=i;
    	while (gets(s)&&strlen(s)){
    		n=strlen(s);
    		for (int i=0,now=1,len=0;i<n;i++){
    			int c=s[i]-'a';
    			if (t[now].Next[c]){
    				len++;
    				now=t[now].Next[c];
    				Max[m][now]=max(Max[m][now],len);
    				continue;
    			}
    			while (!t[now].Next[c])
    				now=t[now].fa;
    			len=t[now].Max+1;
    			now=t[now].Next[c];
    			Max[m][now]=max(Max[m][now],len);
    		}
    		for (int i=size;i>=1;i--)
    			Max[m][t[id[i]].fa]=max(Max[m][t[id[i]].fa],Max[m][id[i]]);
    		m++;
    	}
    	int ans=0;
    	for (int i=1;i<=size;i++){
    		int now=t[i].Max;
    		for (int j=0;j<m;j++)
    			now=min(now,Max[j][i]);
    		ans=max(ans,now);
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    UPD(2018-05-07):

      听说有人要用hash过这题??

    看这个:

    来自陈立杰的后缀自动机课件

  • 相关阅读:
    网页鼠标点击特效
    ElementUI 删除 el-table 当前选中行(不是selection列)
    Vue阻止冒泡
    Vue实现选项卡切换
    Vue的条件渲染
    Vue实现勾选后向数组都添加
    Vue实现商城里面多个商品计算,全选,删除
    VUE实现请求数据
    JS实现数组每次只显示5条数据
    移动端分享到微信和QQ
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/SPOJ-LCS2.html
Copyright © 2011-2022 走看看