Time:2016.05.26
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
首先要求出不同子串的个数
有这样一个性质
一个串中不同子串的总数=∑(len-height[i]-sa[i])
然后就可以通过二分子串的排名,来判断当前排名的子串是否符合要求
比较任意两子串的排名用RMQ求LCP
还有一个问题就是知道排名,求其串。
这个要从后向前枚举,一个个减去就好
注意:
注意下标的处理和后缀数组自身的性质
代码:
#include<bits/stdc++.h>
#define M 100003
#define LL long long
using namespace std;
int len,k,ans_l,ans_r,ls,rs;LL sum;
int cnt[M],w[M],sa[M],rank[M],tmp[M],id[M],height[M],fa[M][18];
char s[M];
void SA(int len,int up)
{
int d=1,p=0,*t=tmp,*rk=rank;
for (int i=0;i<len;i++) cnt[rk[i]=w[i]]++;
for (int i=1;i<up;i++) cnt[i]+=cnt[i-1];
for (int i=len-1;i>=0;i--) sa[--cnt[rk[i]]]=i;
for (;;)
{
for (int i=len-d;i<len;i++) id[p++]=i;
for (int i=0;i<len;i++)
if (sa[i]>=d) id[p++]=sa[i]-d;
for (int i=0;i<up;i++) cnt[i]=0;
for (int i=0;i<len;i++) cnt[t[i]=rk[id[i]]]++;
for (int i=1;i<up;i++) cnt[i]+=cnt[i-1];
for (int i=len-1;i>=0;i--) sa[--cnt[t[i]]]=id[i];
p=1;
swap(t,rk);
rk[sa[0]]=0;
for (int i=0;i<len-1;i++)
if (sa[i]+d<len&&sa[i+1]+d<len&&t[sa[i]]==t[sa[i+1]]&&t[sa[i]+d]==t[sa[i+1]+d])
rk[sa[i+1]]=p-1;
else
rk[sa[i+1]]=p++;
if (p==len) break;
d<<=1;up=p;p=0;
}
}
void Height(int len)
{
for (int i=1;i<=len;i++) rank[sa[i]]=i;
int k=0,x;
for (int i=0;i<len;i++)
{
x=sa[rank[i]-1];
k=max(k-1,0);
while (w[x+k]==w[i+k]) k++;
height[rank[i]]=k;
}
}
void Kth(LL x)
{
LL t=x;
for (int i=1;i<=len;i++)
if (t>len-sa[i]-height[i]) t-=len-sa[i]-height[i];
else {ls=sa[i];rs=sa[i]+height[i]+t-1;return;}
}
int LCP(int a,int b)
{
if (a==b) return len-sa[a];
if (a>b) swap(a,b);
int k=log2(b-a);
return min(fa[a+1][k],fa[b-(1<<k)+1][k]);
}
bool compare(int x1,int y1,int x2,int y2)
{
int l1=y1-x1+1,l2=y2-x2+1,lcp=LCP(rank[x1],rank[x2]);
if (lcp>=l1) return l1<=l2;
else if (lcp>=l2) return 0;
else return s[x1+lcp]<=s[x2+lcp];
}
bool check()
{
int last=len-1,p=1;
for (int i=len-1;i>=0;i--)
if (s[i]>s[ls]) return 0;
else if (!compare(i,last,ls,rs))
{
p++;last=i;
if (p>k) return 0;
}
return 1;
}
main()
{
scanf("%d",&k);
scanf("%s",s);
len=strlen(s);
for (int i=0;i<len;i++) w[i]=s[i]-'a'+1;
SA(len+1,28);
Height(len);
for (int i=1;i<=len;i++) sum+=len-sa[i]-height[i];
for (int i=1;i<=len;i++) fa[i][0]=height[i];
for (int j=1;j<=17;j++)
for (int i=1;i<=len-(1<<j-1);i++)
fa[i][j]=min(fa[i][j-1],fa[i+(1<<j-1)][j-1]);
LL l=1,r=sum,mid;
while (l<=r)
{
mid=l+r>>1;
Kth(mid);
if (check()) ans_l=ls,ans_r=rs,r=mid-1;
else l=mid+1;
}
for (int i=ans_l;i<=ans_r;i++) putchar(s[i]);
}