ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

dtoi4680 红黑兔

2020-01-28 23:54:11  阅读:242  来源: 互联网

标签:return lef int mid fx 红黑 dtoi4680 500002


题意:

     给定一个字符串,长度小于等于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\n",ans);
    return 0;
}

标签:return,lef,int,mid,fx,红黑,dtoi4680,500002
来源: https://www.cnblogs.com/1124828077ccj/p/12239365.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有