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()中,应该两个后缀分列连接字符两侧即可,一开始写的第一个在左侧,第二个在右侧

  • 相关阅读:
    【crontab】误删crontab及其恢复
    New Concept English there (7)
    New Concept English there (6)
    New Concept English there (5)
    New Concept English there (4)
    New Concept English there (3)
    New Concept English there (2)Typing speed exercise
    New Concept English there (1)Typing speed exercise
    New Concept English Two 34 game over
    New Concept English Two 33 94
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6592983.html
Copyright © 2011-2022 走看看