二分+后缀数组。
验证时贪心去验证,能不选尽量不选,这个东西可以求两后缀的LCP然后去判断就可以了。
后缀自动机党怎么能写后缀数组
真香。
代码
/**************************************************************
Problem: 4310
User: sckalrter
Language: C++
Result: Accepted
Time:2064 ms
Memory:12432 kb
****************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
typedef long long ll;
char s[N],ans[N];
int n,m,k,a[N],sa[N],c[N],x[N],y[N],rk[N],h[N],st[N][20],l1=0,r1=0,lg[N];
void getsa(int n,int m){
for (int i=1;i<=n;i++) c[x[i]=a[i]]++;
for (int i=1;i<=m;i++) c[i]+=c[i-1];
for (int i=n;i>=1;i--) sa[c[x[i]]--]=i;
int num=0;
for (int k=1;k<=n;k<<=1){
num=0;
for (int i=n-k+1;i<=n;i++) y[++num]=i;
for (int i=1;i<=n;i++) if (sa[i]>k) y[++num]=sa[i]-k;
for (int i=1;i<=m;i++) c[i]=0;
for (int i=1;i<=n;i++) c[x[i]]++;
for (int i=1;i<=m;i++) c[i]+=c[i-1];
for (int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i];
swap(x,y);
x[sa[1]]=1; num=1;
for (int i=2;i<=n;i++){
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
}
m=num;
if (num==n) return;
}
}
void geth(){
for (int i=1;i<=n;i++) rk[sa[i]]=i;
int k=0;
for (int i=1;i<=n;i++){
if (rk[i]==1) continue;
int j=sa[rk[i]-1];
if (k) k--;
while (j+k<=n&&i+k<=n&&s[j+k]==s[i+k]) k++;
h[rk[i]]=k;
}
}
void pre(){
for (int i=1;i<=n;i++) st[i][0]=h[i];
for (int j=1;j<=17;j++)
for (int i=1;i<=n+1-(1<<(j-1));i++)
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
int query(int l,int r){
if (l==r) return (n-sa[l]);
if (l>r) swap(l,r);
int len=r-l+1;
int k=log2(r-l);
return min(st[l+1][k],st[r-(1<<k)+1][k]);
}
void getk(ll k){
for (int i=1;i<=n;i++){
if (k>n-sa[i]-h[i]) k-=n-sa[i]-h[i];
else{l1=sa[i]+1,r1=h[i]+sa[i]+k; return;}
}
}
bool cmp(int l1,int r1,int l2,int r2){
int len1=r1-l1+1,len2=r2-l2+1;
int lcp=query(rk[l1],rk[l2]);
if (lcp>=len1){ return (len1<=len2);}
if (lcp>=len2){return 0;}
return (s[l1+lcp]<=s[l2+lcp]);
}
bool ck(){
int p=1,las=n;
for (int i=n;i>=1;i--){
if (s[i]>s[l1]) return 0;
if (!cmp(i,las,l1,r1)){
p++; las=i;
if (p>k) return 0;
}
}
return 1;
}
int main(){
scanf("%d",&k);
scanf("%s",s+1);
n=strlen(s+1); m=266;
for (int i=1;i<=n;i++){
a[i]=s[i];
}
getsa(n,m); geth(); pre();
ll sum=0;
for (int i=1;i<=n;i++){
sa[i]--;
sum+=(n-h[i]-sa[i]);
}
ll l=1,r=sum,mid,ans_l=0,ans_r=0;
while (l<=r){
mid=(l+r)>>1;
getk(mid);
if (ck()){ ans_l=l1; ans_r=r1; r=mid-1;} else l=mid+1;
}
for (int i=ans_l;i<=ans_r;i++) putchar(s[i]);
return 0;
}