zoukankan      html  css  js  c++  java
  • codevs 3160 最长公共子串

    3160 最长公共子串

     http://codevs.cn/problem/3160/

     时间限制: 2 s
     空间限制: 128000 KB
     
    题目描述 Description

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

     
    输入描述 Input Description

    读入两个字符串

     
    输出描述 Output Description

    输出最长公共子串的长度

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

    27

     
    数据范围及提示 Data Size & Hint

    单个字符串的长度不超过100000

    将两个字符串中间用未出现过的字符连接起来

    后缀数组

    将后缀按rank排序求出height数组

    然后枚举i height数组,如果sa[i]和sa[i-1]分别位于连接字符的两侧,则ans=max(ans,height[i])

    看后缀数组戳这里http://www.cnblogs.com/TheRoadToTheGold/p/6591534.html

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100010  
    using namespace std;
    int n,p,q=1,k,a[2*N],rk[2][N*2],sa[2][N*2],h[N*2],v[N*2],ans;
    char s1[N*2],s2[N]; 
    int len1,len2;
    void mul(int *sa,int *rk,int *SA,int *RK)
    {
        for(int i=1;i<=n;i++) v[rk[sa[i]]]=i;
        for(int i=n;i;i--) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
        for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i;
        for(int i=1;i<=n;i++) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]); 
    } 
    void presa()
    {
        for(int i=1;i<=n;i++) v[a[i]]++;
        for(int i=1;i<=27;i++) v[i]+=v[i-1];
        for(int i=1;i<=n;i++) sa[p][v[a[i]]--]=i;
        for(int i=1;i<=n;i++)  rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);for(k=1;k<n;k<<=1,swap(p,q)) 
        {
            mul(sa[p],rk[p],sa[q],rk[q]);
            if(rk[q][sa[q][n]]==n) 
            {
                swap(p,q);
                return;
            }
        }
    }
    void getheight()
    {
        int j;
        for(int i=1,g=0;i<=n;i++)
        {
            /*if(rk[p][i]==1) 有没有无所谓 因为h[1]不参与计算 
            {
                h[rk[p][i]]=0;
                continue;
            }*/
            j=sa[p][rk[p][i]-1];
            while(a[i+g]==a[j+g]) g++;
            h[rk[p][i]]=g; if(g) g--;
        } 
    }
    void solve()
    {
        int t1,t2;
        for(int i=2;i<=n;i++)
        {
            t1=sa[p][i];
            t2=sa[p][i-1];
            if((t1>=len1)^(t2>=len1)) ans=max(ans,h[i]);
        }
        printf("%d",ans);
    }
    int main()
    {
        scanf("%s%s",s1+1,s2);
        len1=strlen(s1+1);len2=strlen(s2);
        n=len1;
        s1[++n]='z'+1;
        for(int i=0;i<len2;i++) s1[++n]=s2[i];
        for(int i=1;i<=n;i++) a[i]=s1[i]-'a'+1;
        presa();
        getheight();
        solve();
    }

    2个错误:

    ① 连接字符的选用,这个字符并不能随便选,它关系到presa()中第二重循环的范围

      刚开始用的‘$’,但presa()中第二重循环仍到26,错了,

     修改为选用ascll码在z后一个的字符

    ② solve()中,应该两个后缀分列连接字符两侧即可,一开始写的第一个在左侧,第二个在右侧

  • 相关阅读:
    Python中的时间
    Python + Selenium 自动化环境搭建过程
    HTML手写课程表,练基础
    temp2
    Jenkins配置文件
    Jenkins安装Slave节点
    Jenkins管理插件
    常见的linux上的服务重启脚本
    测试感慨
    docker的安装
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6592983.html
Copyright © 2011-2022 走看看