• [POI2000] 公共串


    [POI2000] 公共串

    Description

    给出几个由小写字母构成的单词,求它们最长的公共子串的长度。

    Solution

    预处理出后缀数组和高度数组,二分答案 (k) ,对于每一个连续的 (RMQ) 大于等于 (k) 的段,判断其中是否有来源于每一个串的后缀即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    int n,m=256,sa[1000005],y[1000005],u[1000005],v[1000005],o[1000005],r[1000005],h[1000005],T;
    // sa: Suffix Array
    // r: Rank Array
    // h: Height Array (between sa[i] & sa[i-1])
    char str[1000005];
    long long ans;
    int bel[1000005];
    int buf[10];
    
    int main()
    {
        string s[6];
        int T;
        cin>>T;
        for(int i=1; i<=T; i++) cin>>s[i];
    
        int pin=0;
        for(int i=1; i<=T; i++)
        {
            for(int j=1; j<=s[i].length(); j++)
                str[pin+j]=s[i][j-1],
                           bel[pin+j]=i;
            str[pin+s[i].length()+1]='z'+(char)i;
            pin+=s[i].length()+1;
        }
        n=strlen(str+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=1e+9;
            for(int i=1; i<=T; i++) r=min(r,(int)s[i].length());
            ++r;
            while(l<r)
            {
                int mid = (l+r)/2;
                int i=1,j=1,flag=0;
                while(i<=n && j<=n)
                {
                    j=i;
                    while(h[j+1]>=mid) ++j;
                    for(int k=1; k<=T; k++) buf[k]=0;
                    for(int k=i; k<=j; k++) buf[bel[sa[k]]]=1;
                    int fg=1;
                    for(int k=1; k<=T; k++) if(buf[k]==0) fg=0;
                    if(fg) flag = 1;
                    i=j+1;
                }
                if(flag) l=mid+1;
                else r=mid;
            }
            cout<<l-1<<endl;
        }
    
    }
    
  • 相关阅读:
    升级Xcode之后VVDocumenter-Xcode不能用的解决办法
    iOS国际化
    display:table 表格布局
    display: run-in
    连续字符换行 溢出点点点 多行省略
    Number 类型
    Boolean 相关
    Browsing contexts 浏览器上下文
    return flase 作用
    JS外链
  • 原文地址:https://www.cnblogs.com/mollnn/p/11765724.html
Copyright © 2020-2023  润新知