spoj Longest Common Substring (多串求最大公共子序列)

Posted carcar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spoj Longest Common Substring (多串求最大公共子序列)相关的知识,希望对你有一定的参考价值。

题目链接:

https://vjudge.net/problem/SPOJ-LCS

题意:

最多10行字符串

求最大公共子序列

数据范围:

$1\leq |S| \leq100000$

分析: 

让他们都和第一个字符串匹配,算出每个字符串与第一个字符串的,以$i$位置(i指的是在s1中的位置)结尾匹配的最大长度

与其它字符串的匹配取最小值

最后对所有位置取最大值

超时代码:(题限是236ms,这个代码跑2000ms没问题)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=500000*2+7;
char S[maxn];
char S1[maxn/2];
int ans[maxn/2];
int n,a,b,len1,len2;
struct suffixautomation

    int mp[maxn*2][30],fa[maxn*2],ed,ct,len[maxn*2],minpos[maxn*2],maxpos[maxn*2],deg[maxn*2];
    int res[maxn/2];
    suffixautomation()
        for(int i=0;i<maxn*2;i++)minpos[i]=1e9,maxpos[i]=-1;
        ed=ct=1;
    inline void ins(int c,int pos)
    
        int p=ed;ed=++ct;minpos[ed]=maxpos[ed]=pos;len[ed]=pos;//先初始化size和len
        for(;p&&mp[p][c]==0;p=fa[p])mp[p][c]=ed;//然后顺着parent树的路径向上找
        if(p==0)fa[ed]=1;return;int q=mp[p][c];//case1
        if(len[p]+1==len[q])fa[ed]=q;return;//case2
        len[++ct]=len[p]+1;//case 3
        for(int i=1;i<=26;i++)mp[ct][i]=mp[q][i];
        fa[ct]=fa[q];fa[q]=ct;fa[ed]=ct;
        for(int i=p;mp[i][c]==q;i=fa[i])mp[i][c]=ct;
    
    void solve()

        for(int i=1;i<=ct;i++)deg[fa[i]]++;
        queue<int>que;
        for(int i=1;i<=ct;i++)if(deg[i]==0)que.push(i);
        while(que.size())
            int x=que.front();
            int y=fa[x];
            que.pop();
            minpos[y]=min(minpos[x],minpos[y]);
            maxpos[y]=max(maxpos[x],maxpos[y]);
            deg[y]--;
            if(deg[y]==0)que.push(y);
        
        for(int i=1;i<=ct;i++)
            if(minpos[i]<=len1&&maxpos[i]>=len1+2)
                res[minpos[i]]=max(res[minpos[i]],len[i]);
    
sam,sam2;
int main()

//    cout<<"acfvd"
    for(int i=0;i<maxn/2;i++)ans[i]=1e9;
    scanf("%s",S+1);
    len1=strlen(S+1);
    S[len1+1]=‘z‘+1;
    while(scanf("%s",S1+1)==1)
         len2=strlen(S1+1);
         sam=sam2;
         for(int i=len1+2;i<=len1+len2+1;i++)
            S[i]=S1[i-len1-1];
        for(int i=1;i<=len1+len2+1;i++)sam.ins(S[i]-‘a‘+1,i);
        sam.solve();
        for(int i=1;i<=len1;i++)
            ans[i]=min(ans[i],sam.res[i]);
    
    int res=0;
    for(int i=1;i<=len1;i++)
        if(ans[i]!=1e9)res=max(res,ans[i]);
    printf("%d\n",res);
    return 0;

  

以上是关于spoj Longest Common Substring (多串求最大公共子序列)的主要内容,如果未能解决你的问题,请参考以下文章

刷题SPOJ 1811 LCS - Longest Common Substring

SPOJ 1811 Longest Common Substring

Spoj LCS2 - Longest Common Substring II

spoj1812 LCS2 - Longest Common Substring II

SPOJ 1811 Longest Common Substring

后缀自动机(SAM):SPOJ Longest Common Substring II