其他分享
首页 > 其他分享> > Ybtoj #534. 「后缀数组」跳蚤的串

Ybtoj #534. 「后缀数组」跳蚤的串

作者:互联网

题面传送门
最大值最小显然想到二分。
因为答案肯定是原序列的一个子串,所以直接二分这个子串在本质不同子串中的排名即可。
因为已经预处理了SA,所以在check的时候倒叙,显然一个后缀中字典序最大的串是最长的子串,所以倒叙以后,如果当前点的字典序大于二分的字典序,那么这个位置和上一个位置就必须要分开。这样如果最终段数大于\(k\)则失败,否则成功。
时间复杂度\(O(n\log n)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 100000
#define M N*N+5
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*x+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound  
using namespace std;
int n,m,k,x,y,lg[N+5];char S[N+5];ll l,r,mid,ToT;
namespace SA{
	int H[N+5],sa[N+5],rk[N+5],st[N+5][20];
	struct Ques{int x,y,id;}F[N+5];I bool cmp(Ques x,Ques y){return x.x^y.x?x.x<y.x:x.y<y.y;}
	I void BD(){
		RI i,j;for(i=1;i<=n;i++) F[i]=(Ques){S[i],0,i};sort(F+1,F+n+1,cmp);for(i=1;i<=n;i++) rk[F[i].id]=rk[F[i-1].id]+(F[i].x^F[i-1].x||F[i].y^F[i-1].y);
		for(i=1;i<=n;i<<=1){for(j=1;j<=n;j++) F[j]=(Ques){rk[j],i+j<=n?rk[i+j]:0,j};sort(F+1,F+n+1,cmp);for(j=1;j<=n;j++) rk[F[j].id]=rk[F[j-1].id]+(F[j].x^F[j-1].x||F[j].y^F[j-1].y);if(rk[F[n].id]==n) break;}
		for(i=1;i<=n;i++) sa[rk[i]]=i;for(i=2;i<=n;i++){lg[i]=lg[i/2]+1;H[i]=max(H[rk[sa[i]-1]]-1,0);while(S[sa[i]+H[i]]==S[sa[i-1]+H[i]]) H[i]++;}
		for(i=n;i>1;i--) for(st[i][0]=H[i],j=1;i+(1<<j)-1<=n;j++) st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);for(i=1;i<=n;i++) ToT+=n-sa[i]+1-H[i];
	}
	I int LCP(int x,int y){if(x==y) return n-x+1;x=rk[x];y=rk[y];x>y&&(swap(x,y),0);x++;int d=lg[y-x+1];return min(st[x][d],st[y-(1<<d)+1][d]);}
	I void Find(ll ToT,int &x,int &y){for(RI i=1;i<=n;i++) if(ToT>n-sa[i]+1-H[i]) ToT-=n-sa[i]+1-H[i];else {x=sa[i];y=sa[i]+H[i]+ToT-1;return;}}
}
I int calc(int x,int y,int l,int r){int d=SA::LCP(x,l);if(y-x+1<=d) return r-l+1<=d?(y-x>r-l):0;else return r-l+1<=d?1:(SA::rk[x]^SA::rk[l]?SA::rk[x]>SA::rk[l]:y-x+1>r-l+1);}
I int check(ll mid){SA::Find(mid,x,y);RI i,cnt=0,j,d;for(j=i=n;i;i--){if(calc(i,j,x,y)) cnt++,j=i,i++;if(cnt>k) return 0;}cnt++;return cnt<=k;}
int main(){
	freopen("flea.in","r",stdin);freopen("flea.out","w",stdout);
	RI i;scanf("%d%s",&k,S+1); n=strlen(S+1);SA::BD();l=0;r=ToT;while(l+1<r) mid=l+r>>1,(check(mid)?r:l)=mid;SA::Find(r,x,y);for(i=x;i<=y;i++)Pc(S[i]);
}

标签:cnt,return,int,Ybtoj,mid,534,SA,跳蚤,define
来源: https://www.cnblogs.com/275307894a/p/15865810.html