zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    蓝桥杯 勾股数 暴力
    蓝桥杯 连接乘积 暴力
    蓝桥杯 师座操作系统 map
    蓝桥杯 洗牌 vector
    蓝桥杯 盾神与砝码称重 dfs 剪枝
    蓝桥杯 盾神与积木游戏 贪心
    RESTful风格API
    APIview使用
    linux常用命令
    python中的三种路径
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8286648.html
Copyright © 2011-2022 走看看