zoukankan      html  css  js  c++  java
  • BZOJ 4310 二分+SA+RMQ

    思路:

    首先求出后缀数组和height数组,这样能得到本质不同的子串数目

    这里利用:本质不同的子串=(LenSA[i]height[i])=∑(Len−SA[i]−height[i])利用SA[],height[]的定义很好想

    然后要求最大值最小,显然二分,二分一个mid,求出第mid大的子串

    然后贪心的检验,从后往前扫,当字典序超过二分的值时,划分一下,看划分个数与K的关系即可

    中间涉及比较,用LCP实现即可,显然ST表非常方便

    From Dad3zZ

    //By SiriusRen
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=100050;
    typedef long long ll;
    int n,k,cntA[N],cntB[N],A[N],B[N],sa[N],tsa[N],rk[N],ht[N],Log[N],st[N][20];
    int L,R;ll l,r,ans;
    char s[N];
    void SA(){
        for(int i=1;i<=n;i++)cntA[s[i]]++;
        for(int i=1;i<=256;i++)cntA[i]+=cntA[i-1];
        for(int i=n;i;i--)sa[cntA[s[i]]--]=i;
        rk[sa[1]]=1;
        for(int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]);
        for(int l=1;rk[sa[n]]<n;l<<=1){
            memset(cntA,0,sizeof(cntA));
            memset(cntB,0,sizeof(cntB));
            for(int i=1;i<=n;i++)
                cntA[A[i]=rk[i]]++,
                cntB[B[i]=i+l<=n?rk[i+l]:0]++;
            for(int i=1;i<=n;i++)cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
            for(int i=n;i;i--)tsa[cntB[B[i]]--]=i;
            for(int i=n;i;i--)sa[cntA[A[tsa[i]]]--]=tsa[i];
            rk[sa[1]]=1;
            for(int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(A[sa[i]]!=A[sa[i-1]]||B[sa[i]]!=B[sa[i-1]]);
        }
        for(int i=1,j=0;i<=n;i++){
            j=j?j-1:0,Log[i]=i!=1?Log[i>>1]+1:0;
            while(s[i+j]==s[sa[rk[i]-1]+j])j++;
            st[rk[i]][0]=ht[rk[i]]=j;
        }
        for(int j=1;j<=19;j++)for(int i=1;i+(1<<(j-1))<=n;i++)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    }
    int lcp(int x,int y){
        if(x==y)return n-x+1;
        x=rk[x],y=rk[y];
        if(x>y)swap(x,y);x++;
        int t=Log[y-x+1];
        return min(st[x][t],st[y-(1<<t)+1][t]);
    }
    void get(ll k){
        for(int i=1;i<=n;i++){
            if(n-sa[i]-ht[i]+1<k)k=k-(n-sa[i]-ht[i]+1);
            else{L=sa[i],R=sa[i]+ht[i]+k-1;break;}
        }
    }
    bool cmp(int l1,int r1,int l2,int r2){
        int len1=r1-l1+1,len2=r2-l2+1,LCP=lcp(l1,l2);
        if(len1<=len2&&LCP>=len1)return 1;
        if(len1>len2&&LCP>=len2)return 0;
        if(LCP>=len1&&LCP>=len2)return len1<len2;
        return s[l1+LCP]<s[l2+LCP];
    }
    bool check(){
        int cnt=1,last=n;
        for(int i=n;i;i--){
            if(!cmp(i,last,L,R))cnt++,last=i;
            if(cnt>k)return 0;
        }return 1;
    }
    int main(){
        scanf("%d%s",&k,s+1),n=strlen(s+1),SA();
        for(int i=1;i<=n;i++)r+=n-sa[i]-ht[i]+1;
        while(l<=r){
            ll mid=(l+r)>>1;
            get(mid);
            if(check())r=mid-1,ans=mid;
            else l=mid+1;
        }get(ans);
        s[R+1]=0;printf("%s
    ",s+L);
    }
  • 相关阅读:
    经常使用的两个清爽的table样式
    wdcp新开站点或绑定域名打不开或无法访问的问题
    在线客服代码,可以用
    $smarty获取变量get,post等用法
    mysql 替换某个字段中的某个字符
    git 设置不需要输入密码
    linux批量查找文件内容
    使用PHP QR Code生成二维码
    RabbitMQ-2
    RabbitMQ-1
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6685548.html
Copyright © 2011-2022 走看看