zoukankan      html  css  js  c++  java
  • dtoi4680 红黑兔

    题意:

         给定一个字符串,长度小于等于500000。让你找一个二元组序列(l[i],r[i]),使得区间[l[i+1],r[i+1]]的字符串是区间[l[i],r[i]]的子串。求最长的序列长度。

    题解:

         首先有一个贪心的想法,第i个字符串肯定恰好比第i+1个字符串多一个字符。

         考虑对于位置i,如何判断一个答案mid是否可行,首先要满足的条件就是有一个位置j满足后缀j与后缀i的最长公共前缀>=mid-1,或者是后缀j与后缀i+1的最长公共前缀>=mid-1,这分别对应SA上的一段区间。还要满足的条件就是f[j]>=mid-1且j>i+mid。因此可以建立可持久化线段树,外层为字符串中的下标,内层为SA上的下标。每次就是查询一棵树中一段区间的最大值是否>=mid-1即可判断。

         这个效率是O(n*logn*logn)。其实我们发现并不需要二分,可以证明f[i]<=f[i+1]+1,因此只需要把上限设为f[i+1]+1,然后判断,不合法就减一,再判断......

         于是效率成功变成了O(nlogn)。接着我发现我忘记了后缀数组怎么写,就写了个二分hash,效率依然是两个log。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int INF=1313331;
    int n,t[500002],h[500002],Min[22][500002],f[500002],ans,rt[500002],rk[500002],cnt,lgg[500002];
    unsigned long long has[500002],cf[500002],nf;
    char s[500002];
    typedef struct{
        int Max,ls,rs;
    }P;
    P p[20000002];
    bool pd(int x,int y,int l,int r){
        if (x<l)return (has[y]-has[x-1])*cf[l-x]==(has[r]-has[l-1]);
        else return (has[y]-has[x-1])==(has[r]-has[l-1])*cf[x-l];
    }
    bool cmp(const int& x,const int& y){
        int lef=0,righ=min(n-x+1,n-y+1),mid;
        while(lef<righ)
        {
            mid=(lef+righ+1)/2;
            if (pd(x,x+mid-1,y,y+mid-1))lef=mid;else righ=mid-1;
        }
        if (lef==min(n-x+1,n-y+1))return (x>y);
        return s[x+lef]<s[y+lef];
    }
    void gengxin(int r1,int r2,int begin,int end,int wz,int z){
        if (begin==end)
        {
            p[r1].Max=max(z,p[r2].Max);
            return;
        }
        int mid=(begin+end)/2;
        if (wz<=mid)
        {
            p[r1].ls=++cnt;p[r1].rs=p[r2].rs;
            gengxin(p[r1].ls,p[r2].ls,begin,mid,wz,z);
        }
        else
        {
            p[r1].rs=++cnt;p[r1].ls=p[r2].ls;
            gengxin(p[r1].rs,p[r2].rs,mid+1,end,wz,z);
        }
        p[r1].Max=max(p[p[r1].ls].Max,p[p[r1].rs].Max);
    }
    int chaxun(int root,int begin,int end,int begin2,int end2){
        if (begin>end2 || end<begin2)return 0;
        if (begin>=begin2 && end<=end2)return p[root].Max;
        int mid=(begin+end)/2;
        return max(chaxun(p[root].ls,begin,mid,begin2,end2),chaxun(p[root].rs,mid+1,end,begin2,end2));
    }
    int minh(int x,int y){
        int len=y-x+1;
        return min(Min[lgg[len]][x],Min[lgg[len]][y-(1<<lgg[len])+1]);
    }
    int ef1(int x,int y,int z){
        int lef=x,righ=y,mid;
        while(lef<righ)
        {
            mid=(lef+righ)/2;
            if (minh(mid,y-1)>=z)righ=mid;else lef=mid+1;
        }
        return lef;
    }
    int ef2(int x,int y,int z){
        int lef=x,righ=y,mid;
        while(lef<righ)
        {
            mid=(lef+righ+1)/2;
            if (minh(x,mid-1)>=z)lef=mid;else righ=mid-1;
        }
        return lef;
    }
    bool pdd(int x,int fx){
        if (fx==1)return 1;
        int l=ef1(1,rk[x],fx-1),r=ef2(rk[x],n,fx-1);
        if (chaxun(rt[x+fx],1,n,l,r)>=fx-1)return 1;
        l=ef1(1,rk[x+1],fx-1);r=ef2(rk[x+1],n,fx-1);
        if (chaxun(rt[x+fx],1,n,l,r)>=fx-1)return 1;
        return 0;
    }
    int main()
    {
        scanf("%s",s+1);n=strlen(s+1);
        nf=1;cf[0]=1;
        for (int i=1;i<=n;i++)
        {
            has[i]=has[i-1]+s[i]*nf;
            nf*=INF;cf[i]=nf;t[i]=i;
        }
        sort(t+1,t+n+1,cmp);
        for (int i=1;i<=n;i++)
        for (int j=0;(1<<j)<=i;j++)lgg[i]=j;
        for (int i=1;i<=n;i++)rk[t[i]]=i;
        for (int i=1;i<n;i++)
        {
            int x=t[i],y=t[i+1];
            int lef=0,righ=min(n-x+1,n-y+1),mid;
            while(lef<righ)
            {
                mid=(lef+righ+1)/2;
                if (pd(x,x+mid-1,y,y+mid-1))lef=mid;else righ=mid-1;
            }
            Min[0][i]=h[i]=lef;
        }
        for (int i=1;i<=20;i++)
        for (int j=1;j<=n;j++)
        Min[i][j]=min(Min[i-1][j],Min[i-1][j+(1<<i-1)]);
        for (int i=n;i>=1;i--)
        {
            f[i]=f[i+1]+1;
            while(!pdd(i,f[i]))f[i]--;
            rt[i]=++cnt;
            gengxin(rt[i],rt[i+1],1,n,rk[i],f[i]);
            ans=max(ans,f[i]);
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    关闭编辑easyui datagrid table
    sql 保留两位小数+四舍五入
    easyui DataGrid 工具类之 util js
    easyui DataGrid 工具类之 后台生成列
    easyui DataGrid 工具类之 WorkbookUtil class
    easyui DataGrid 工具类之 TableUtil class
    easyui DataGrid 工具类之 Utils class
    easyui DataGrid 工具类之 列属性class
    oracle 卸载
    “云时代架构”经典文章阅读感想七
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12239365.html
Copyright © 2011-2022 走看看