codevs 3160 最长公共子串

Posted 蒟蒻JHY

tags:

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

 3160 最长公共子串
 
 时间限制: 2 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
 
 
题目描述 Description

给出两个由小写字母组成的字符串,求它们的最长公共子串的长度。

 

输入描述 Input Description

读入两个字符串

 

输出描述 Output Description

输出最长公共子串的长度

 

样例输入 Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother
 
样例输出 Sample Output

27

 

数据范围及提示 Data Size & Hint

单个字符串的长度不超过100000
   技术分享图片

   最近迷上字符串来hhhhh
这个题的解法比较巧妙,我们把两个字符串中间随便加一个不会出现的字符然后连起来做后缀数组,求出height之后,
如果sa[i]和sa[i-1]不在同一字符串中,我们就可以用height[i]更新答案。

这样得到的答案显然是最优的,因为求lcp是在height上的rmq,而显然rank不相邻的两个位置答案不会比相邻的更优。

 

#include<bits/stdc++.h>
#define ll long long
#define maxn 200005
using namespace std;
char s[maxn];
int sa[maxn],sax[maxn];
int rank[maxn<<1],rankx[maxn];
int cc[maxn],height[maxn];
int n,m,len,ans=0,sec[maxn];

inline int pos(int x){
    return x<n;
}

inline void get_height(){
    for(int i=0;i<len;i++) cc[s[i]]++;
    for(int i=1;i<=500;i++) cc[i]+=cc[i-1];
    for(int i=0;i<len;i++) sa[cc[s[i]]--]=i;
    for(int i=1;i<=len;i++){
        rank[sa[i]]=i;
        if(i>1&&s[sa[i]]==s[sa[i-1]]) rank[sa[i]]=rank[sa[i-1]];
    }
    
    int k=1;
    while(k<len){
        memset(cc,0,sizeof(cc));
        for(int i=0;i<len;i++) cc[sec[i]=rank[i+k]]++;
        for(int i=len-1;i>=0;i--) cc[i]+=cc[i+1];
        for(int i=0;i<len;i++) sax[cc[sec[i]]--]=i;
        
        memset(cc,0,sizeof(cc));
        for(int i=0;i<len;i++) cc[rank[i]]++;
        for(int i=1;i<=len;i++) cc[i]+=cc[i-1];
        for(int i=1;i<=len;i++) sa[cc[rank[sax[i]]]--]=sax[i];
        
        for(int i=1;i<=len;i++){
            rankx[sa[i]]=i;
            if(i>1&&rank[sa[i]]==rank[sa[i-1]]&&sec[sa[i]]==sec[sa[i-1]]) rankx[sa[i]]=rankx[sa[i-1]];
        }
        
        for(int i=0;i<len;i++) rank[i]=rankx[i];
        k<<=1;
    }
    
    int now=0,j,mx;
    for(int i=0;i<len;i++){
        if(rank[i]==1){
            now=height[rank[i]]=0;
            continue;
        }
        if(now) now--;
        j=sa[rank[i]-1],mx=max(j,i);
        while(mx+now<len&&s[i+now]==s[j+now]) now++;
        height[rank[i]]=now;
    }
    
}

int main(){
    scanf("%s",s);
    n=strlen(s);
    s[n]=~;
    scanf("%s",s+n+1);
    len=strlen(s);
    
    get_height();
    for(int i=2;i<=len;i++) if(pos(sa[i])^pos(sa[i-1])) ans=max(ans,height[i]);
    printf("%d\n",ans);
    return 0;
}

 









以上是关于codevs 3160 最长公共子串的主要内容,如果未能解决你的问题,请参考以下文章

codevs 3160 最长公共子串(SAM)

求最长公共子串

3160 最长公共子串

动态规划——最长公共子序列与最长公共子串 (含Python实现代码)

两个字符串的最长公共子串python代码

最长公共子串与最长公共子序列