其他分享
首页 > 其他分享> > BZOJ4310 跳蚤

BZOJ4310 跳蚤

作者:互联网

跳蚤

给定一个字符串 \(S\),你需要将它分成不超过 \(m\) 个连续子串,使得分割后的所有串的子串中字典序最大的尽量小

\(|S| ≤ 10^5\)

题解

考虑二分答案,可以二分最大的那个子串,然后用后缀树求出。

从后往前,只要不需要切断,就不切断,切断的判断很容易用判 LCP 实现。

最后 check 断点是否不超过 m 个即可

时间复杂度 \(O(n \log n)\)。

CO int N=2e5+10,inf=1e9;
int last=1,tot=1;
int ch[N][26],fa[N],len[N],pos[N],idx[N];

void extend(int c,int p){
    int x=last,cur=last=++tot;
    len[cur]=len[x]+1,pos[cur]=p,idx[p]=cur;
    for(;x and !ch[x][c];x=fa[x]) ch[x][c]=cur;
    if(!x) {fa[cur]=1;return;};
    int y=ch[x][c];
    if(len[y]==len[x]+1) {fa[cur]=y;return;}
    int clone=++tot;
    copy(ch[y],ch[y]+26,ch[clone]);
    fa[clone]=fa[y],len[clone]=len[x]+1,pos[clone]=pos[cur];
    fa[cur]=fa[y]=clone;
    for(;ch[x][c]==y;x=fa[x]) ch[x][c]=clone;
}

int son[N][26];
int sa[N];int64 sum[N];
int rnk[N],st[2*N][19],lg[2*N];

void dfs(int x){
    sa[++sa[0]]=x,sum[sa[0]]=len[x]-len[fa[x]];
    st[rnk[x]=++rnk[0]][0]=len[x];
    for(int c=0;c<26;++c)if(son[x][c]){
        dfs(son[x][c]);
        st[++rnk[0]][0]=len[x];
    }
}
int lcp(int i,int j){
    i=rnk[idx[i]],j=rnk[idx[j]];
    if(i>j) swap(i,j);
    int k=lg[j-i+1];
    return min(st[i][k],st[j-(1<<k)+1][k]);
}
pair<int,int> search(int64 lim){
    int l=1,r=sa[0];
    while(l<r){
        int mid=(l+r+1)>>1;
        if(sum[mid]<lim) l=mid;
        else r=mid-1;
    }
    lim-=sum[l];
    int x=sa[l+1];
    return {pos[x],pos[x]+len[fa[x]]+lim-1};
}

char str[N],maxc;

int solve(int n,CO pair<int,int>&x){
    if(str[x.first]!=str[0]) return inf;
    int ans=0;
    for(int l=n,r=n;l>=1;--l){
        int len=min(lcp(l,x.first),min(r-l+1,x.second-x.first+1));
        char a=len<r-l+1?str[l+len]:0;
        char b=len<x.second-x.first+1?str[x.first+len]:0;
        if(a>b) ++ans,r=l;
    }
    return ++ans;
}
int main(){
    int K=read<int>();
    scanf("%s",str+1);
    int n=strlen(str+1);
    for(int i=n;i>=1;--i) extend(str[i]-'a',i);
    for(int i=2;i<=tot;++i)
        son[fa[i]][str[pos[i]+len[fa[i]]]-'a']=i;
    dfs(1);
    for(int i=2;i<=sa[0];++i) sum[i]+=sum[i-1];
    for(int i=2;i<=rnk[0];++i) lg[i]=lg[i>>1]+1;
    for(int j=1;j<=lg[rnk[0]];++j)for(int i=1;i+(1<<j)-1<=rnk[0];++i)
        st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    for(int i=1;i<=n;++i) str[0]=max(str[0],str[i]);
    int64 l=1,r=sum[sa[0]];
    while(l<r){
        int64 mid=(l+r)>>1;
        if(solve(n,search(mid))<=K) r=mid;
        else l=mid+1;
    }
    pair<int,int> x=search(l);
    for(int i=x.first;i<=x.second;++i) putchar(str[i]);
    return 0;
}

标签:ch,cur,int,clone,len,fa,BZOJ4310,跳蚤
来源: https://www.cnblogs.com/autoint/p/12340776.html