zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    x01.Weiqi.6: 立体棋子
    x01.Game.MapEditor: 地图编辑器
    SQL Server插入中文出现乱码??的解决办法
    Cachecontrol使用:header('Cachecontrol:private')
    验证身份证号码Javascript代码
    .Net GDI+缩放绘图
    Access(JETSQL)问题集锦
    Android开发中Google谷歌地图坐标系怎么转Baidu百度地图坐标系
    21、桥接模式(Bridge模式)详解
    22、装饰模式(装饰设计模式)详解
  • 原文地址:https://www.cnblogs.com/autoint/p/12340776.html
Copyright © 2011-2022 走看看