zoukankan      html  css  js  c++  java
  • [Codechef SSTORY] A Story with Strings

    [Codechef SSTORY] A Story with Strings

    Description

    给定两个字符串,求它们的最长公共子串。如果解不唯一,输出最先在第二个字符串中出现的那个。

    Solution

    仍然考虑二分答案,然后每次检验连续的一块中是否有来自两个串的后缀出现。

    最后额外处理一次,每次检验连续的一块中是否有来自两个串的后缀出现,在有的情况下利用所有来源于第二个串的后缀得到可能的最小位置即可。

    竟然二分边界忘记加一,我TM真是个憨憨

    #include <bits/stdc++.h>
    using namespace std;
    
    int n,l1,l2,m=256,sa[1000005],y[1000005],u[1000005],v[1000005],o[1000005],r[1000005],h[1000005],T;
    char str[1000005];
    long long ans;
    
    int main()
    {
        scanf("%s",str+1);
        l1=strlen(str+1);
        str[l1+1]='$';
        scanf("%s",str+l1+2);
        l2=strlen(str+l1+2);
        n=l1+l2+1;
    
        for(int i=1; i<=n; i++) u[str[i]]++;
        for(int i=1; i<=m; i++) u[i]+=u[i-1];
        for(int i=n; i>=1; i--) sa[u[str[i]]--]=i;
        r[sa[1]]=1;
        for(int i=2; i<=n; i++) r[sa[i]]=r[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);
    
        for(int l=1; r[sa[n]]<n; l<<=1)
        {
            memset(u,0,sizeof u);
            memset(v,0,sizeof v);
            memcpy(o,r,sizeof r);
            for(int i=1; i<=n; i++) u[r[i]]++, v[r[i+l]]++;
            for(int i=1; i<=n; i++) u[i]+=u[i-1], v[i]+=v[i-1];
            for(int i=n; i>=1; i--) y[v[r[i+l]]--]=i;
            for(int i=n; i>=1; i--) sa[u[r[y[i]]]--]=y[i];
            r[sa[1]]=1;
            for(int i=2; i<=n; i++) r[sa[i]]=r[sa[i-1]]+((o[sa[i]]!=o[sa[i-1]])||(o[sa[i]+l]!=o[sa[i-1]+l]));
        }
        {
            int i,j,k=0;
            for(int i=1; i<=n; h[r[i++]]=k)
                for(k?k--:0,j=sa[r[i]-1]; str[i+k]==str[j+k]; k++);
        }
    
        int L=1,R=min(l1,l2)+1;
        while(L<R)
        {
            int mid=(L+R)/2, flag=0;
            int i=1,j=1;
            while(i<=n && j<=n)
            {
                j=i;
                while(h[j+1]>=mid) ++j;
                int fg1=0,fg2=0;
                for(int k=i; k<=j; k++)
                {
                    if(sa[k]<=l1) fg1=1;
                    if(sa[k]>l1+1) fg2=1;
                }
                if(fg1 && fg2) flag=1;
                i=j+1;
            }
            if(flag) L=mid+1;
            else R=mid;
        }
    
        if(L-1==0)
        {
            printf("0
    ");
            return 0;
        }
        int mx = n+1;
        int i=1,j=1;
        while(i<=n && j<=n)
        {
            j=i;
            while(h[j+1]>=L-1) ++j;
            int fg1=0,fg2=0;
            for(int k=i; k<=j; k++)
            {
                if(sa[k]<=l1) fg1=1;
                if(sa[k]>l1+1) fg2=1;
            }
            if(fg1 && fg2)
            {
                for(int k=i; k<=j; k++)
                    if(sa[k]>l1+1) mx=min(mx,sa[k]);
            }
            i=j+1;
        }
        for(int k=0; k<L-1; k++) printf("%c",str[mx+k]);
        printf("
    %d
    ",L-1);
    }
    
  • 相关阅读:
    ASP.NET验证控件的使用 拓荒者
    读书笔记:MFC单文档应用程序结构分析 拓荒者
    MFC单文档(SDI)全屏程序的实现 拓荒者
    jQuery的animate函数
    设备尺寸杂谈:响应性Web设计中的尺寸问题
    Yeoman学习与实践笔记
    IE对文档的解析模式及兼容性问题
    推荐给开发和设计人员的iPad应用
    几个移动应用统计平台
    颜色、网页颜色与网页安全色
  • 原文地址:https://www.cnblogs.com/mollnn/p/11776388.html
Copyright © 2011-2022 走看看