bzoj4310: 跳蚤

二分+后缀数组;

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<(n);i++)
#define rep2(i,k,n)for(int i=k;i>=(n);i--)
using namespace std;
const int maxn=100105;
typedef long long ll;
int K,sa[maxn],he[maxn],p1[maxn],p2[maxn],c[maxn],rank[maxn],sig=500,n,rmq[maxn][18],pw[18],Log[maxn],top=0,id[maxn],len;
ll g[maxn];
char s[maxn];
void build_sa(){
    int* x=p1;int* y=p2;
    rep(i,0,n)c[x[i]=s[i]]++;
    rep(i,1,sig)c[i]+=c[i-1];
    rep2(i,n-1,0)sa[--c[x[i]]]=i;
    for(int h=1;h<=n;h<<1){int t=0;
        rep(i,n-h,n)y[t++]=i;rep(i,0,n)if(sa[i]>=h)y[t++]=sa[i]-h;
        rep(i,0,sig)c[i]=0;
        rep(i,0,n)c[x[y[i]]]++;
        rep(i,1,sig)c[i]+=c[i-1];
        rep2(i,n-1,0)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);t=0;
        x[sa[0]]=0;
        rep(i,1,n)x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+h]==y[sa[i-1]+h] ? t : ++t;
        t++;if(t>=n)break;
        sig=t;
    }
    rep(i,0,n)rank[sa[i]]=i;
    int j=0;
    rep(i,0,n){if(!rank[i])continue;
    if(j)j--;
        int k=sa[rank[i]-1];
        while(s[i+j]==s[k+j])j++;
        he[rank[i]]=j;
    }
}
void init(){pw[0]=1;
    rep(i,1,17)pw[i]=pw[i-1]<<1;
    rep(i,2,maxn)Log[i]=Log[i>>1]+1;
    rep(i,0,n)rmq[i][0]=he[i];
    rep(i,1,17)rep(j,0,n)if(j+pw[i-1]<n)rmq[j][i]=min(rmq[j][i-1],rmq[j+pw[i-1]][i-1]); //if(j+pw[i-1]<n)
    ll ss=0;
    rep(i,0,n){ss+=n-sa[i]-he[i];g[++top]=ss;id[top]=i;}
}
int lcp(int x,int y){if(x==y)return n-x; //
x=rank[x],y=rank[y];
if(x>y)swap(x,y);
    int t=Log[y-x];
    return min(rmq[x+1][t],rmq[y-pw[t]+1][t]); //
}
int nowl,nowr,ansl,ansr;
void kth(ll k){int t=lower_bound(g+1,g+top+1,k)-g;
    nowl=sa[id[t]];nowr=nowl+he[id[t]]+k-g[t-1]-1;len=nowr-nowl+1;
}
bool pan(int l,int r){
    int t=min(lcp(l,nowl),min(len,r-l+1));
    if(t==r-l+1 && t<=len)return 1;
    if(t==len)return 0;
    return s[l+t]<=s[nowl+t];
}

bool ok(){int k=0;
    int i=n-1,j=n-1;
    while(i>=0){
        while(j>=0 && pan(j,i))j--;
        if(i==j)return 0;
        k++;i=j;
    }
    return (k<=K);
}
int main(){//freopen("in.in","r",stdin);
    scanf("%d",&K);
    scanf("%s",s);n=strlen(s);
    build_sa();
    init();
    ll l=0,r=g[top];  //
    while(l<=r){
        ll mid=(l+r)>>1;
        kth(mid);
        if(ok()){ansl=nowl,ansr=nowr,r=mid-1;}
        else l=mid+1;
    }
    rep(i,ansl,ansr+1)putchar(s[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值