题意
内存限制:256 MiB
时间限制:1000 ms
很久很久以前,森林里住着一群跳蚤。一天,跳蚤国王得到了一个神秘的字符串,它想进行研究。
首先,他会把串分成不超过
k
k
k 个子串,然后对于每个子串
S
S
S,他会从
S
S
S 的所有子串中选择字典序最大的那一个,并在选出来的
k
k
k
个子串中选择字典序最大的那一个。他称其为“魔力串”。现在他想找一个最优的分法让“魔力串”字典序最小。
k ≤ 15 k \le 15 k≤15 , ∣ S ∣ ≤ 1 0 5 |S| \le 10^5 ∣S∣≤105
题解
利用
S
A
M
/
S
A
SAM/SA
SAM/SA 求出本质不同串个数,进行二分
对于
m
i
d
mid
mid ,利用
S
A
M
/
S
A
SAM/SA
SAM/SA 求出其对应的子串
s
s
s
因为一个串的最大字典序子串一定是其后缀(可以画个图理解一下,所以从后往前枚举,如果
[
i
,
l
a
s
t
]
[i,last]
[i,last] 的字典序比
s
s
s 大,则必须在
[
i
−
1
,
l
a
s
t
]
[i-1,last]
[i−1,last] 分割,
i
i
i 作为新的一个
l
a
s
t
last
last
求字典序只需求出最长公共前缀,可以二分
h
a
s
h
hash
hash 或者
S
A
SA
SA 进行处理
我写的是
S
A
M
SAM
SAM +二分
h
a
s
h
hash
hash ,效率
O
(
n
l
o
g
n
−
n
l
o
g
2
n
)
O(nlogn-nlog^2n)
O(nlogn−nlog2n)(我也不会分析了
#include <bits/stdc++.h>
#define K 793999
#define LL long long
#define U unsigned LL
using namespace std;
const int N=2e5+5;
int k,n,lst=1,sz=1,t[N],e[N],tp;
LL s[N],f[N];U b[N],h[N][2];
char str[N],now[N];
struct SAM{
int link,len,nx[26];
}a[N];
void build(int x){
int np=++sz,p=lst;
a[np].len=a[p].len+1;
while(p && !a[p].nx[x])
a[p].nx[x]=np,p=a[p].link;
if (!p) a[np].link=1;
else{
int q=a[p].nx[x];
if (a[q].len==a[p].len+1)
a[np].link=q;
else{
int nq=++sz;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].link=a[np].link=nq;
while(p && a[p].nx[x]==q)
a[p].nx[x]=nq,p=a[p].link;
}
}
lst=np;
}
void find(int u,LL v){
v-=f[u];if (!v) return;
for (int j,i=0;i<26;i++)
if ((j=a[u].nx[i])){
if (v>s[j]) v-=s[j];
else{
now[++tp]=i+'a',find(j,v);
return;
}
}
}
U H(int l,int r,bool ty){
return h[r][ty]-h[l-1][ty]*b[r-l+1];
}
bool cmp(int L,int R){
int d,l=0,r=min(tp,R-L+1);
while(l<r){
d=(l+r+1)>>1;
if (H(1,d,1)==H(L,L+d-1,0))
l=d;
else r=d-1;
}
if (l==min(tp,R-L+1))
return tp>=R-L+1;
return str[L+l]<now[l+1];
}
bool J(){
int res=0;
for (int l=n,r=n;l;){
while(cmp(l,r) && l) l--;
if (l==r) return 0;res++;r=l;
if (res>k) return 0;
}
return 1;
}
int main(){
scanf("%d%s",&k,str+1);
b[0]=1;n=strlen(str+1);
for (int i=1;i<=n;i++)
build(str[i]-'a'),b[i]=b[i-1]*K,
h[i][0]=h[i-1][0]*K+str[i];
for (int i=1;i<=sz;i++) e[a[i].len]++,f[i]=1;
for (int i=1;i<=sz;i++) e[i]+=e[i-1];f[1]=0;
for (int i=1;i<=sz;i++) t[e[a[i].len]--]=i;
for (int j,i=sz;i;i--){
j=t[i];s[j]=f[j];
for (int l=0;l<26;l++)
s[j]+=s[a[j].nx[l]];
}
LL l=1,r=s[1],d;while(l<r){
d=(l+r)>>1;tp=0;find(1,d);
for (int i=1;i<=tp;i++)
h[i][1]=h[i-1][1]*K+now[i];
if (J()) r=d;else l=d+1;
}
tp=0;find(1,l);
for (int i=1;i<=tp;i++) putchar(now[i]);putchar('\n');
return 0;
}