题目:BZOJ3998.
题目大意:给定一个串
S
S
S和一个数
T
T
T,求
S
S
S的第
k
k
k小子串,若
T
=
0
T=0
T=0表示子串重复算一个,否则不算一个,若子串数不到
k
k
k个输出
−
1
-1
−1.
1
≤
∣
S
∣
≤
5
∗
1
0
5
,
0
≤
T
≤
1
1\leq |S|\leq 5*10^5,0\leq T\leq 1
1≤∣S∣≤5∗105,0≤T≤1.
首先看到子串就对 S S S建立SAM.
建立SAM后,我们根据 T T T分类讨论,先考虑 T = 0 T=0 T=0的情况.
首先着第 k k k小的子串可以先考虑直接从原点出发,从小到大枚举所有字符转移边.若这条字符转移边到达的状态可以构成的子串数量不足 k k k个,则肯定不往这条字符转移边转移,直接让 k k k减掉这个值,然后尝试下一条字符转移边;否则进入这条字符转移边即可.
考虑何时停止,很明显通过之前的路径到达当前状态构成的子串是唯一的,所以只要当前 k k k为 1 1 1就可以停止了.
再来考虑如何求出每一个状态开始可以构成的子串数量,很明显我们可以用DP来预处理出这些值,设
f
[
i
]
f[i]
f[i]为到状态
i
i
i可以构成的数量,那么:
f
[
x
]
=
1
+
∑
(
x
,
y
)
∈
E
f
[
y
]
f[x]=1+\sum_{(x,y)\in E}f[y]
f[x]=1+(x,y)∈E∑f[y]
T = 1 T=1 T=1的情况其实类似,只是这样子一个状态可以表示的子串数量就要乘上它所代表的Right集合大小了.
时间复杂度 O ( ∣ S ∣ Σ ) O(|S|\Sigma) O(∣S∣Σ).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=500000,C=26;
int n,t,k;
char c[N+9],sc[N+9];
struct automaton{
int s[C],len,par;
}tr[N*2+9];
int cn,last,rght[N*2+9];
void Build_sam(){last=cn=1;}
void extend(int x){
int np=++cn,p=last;
tr[np].len=tr[p].len+1;rght[np]=1;
last=np;
while (p&&!tr[p].s[x]) tr[p].s[x]=np,p=tr[p].par;
if (!p) tr[np].par=1;
else{
int q=tr[p].s[x];
if (tr[p].len+1==tr[q].len) tr[np].par=q;
else{
tr[++cn]=tr[q];tr[cn].len=tr[p].len+1;
tr[q].par=tr[np].par=cn;
while (p&&tr[p].s[x]==q) tr[p].s[x]=cn,p=tr[p].par;
}
}
}
int q[N*2+9],v[N+9],sum[N*2+9];
void pre(){
int tt;
for (int i=1;i<=cn;++i) ++v[tr[i].len];
for (int i=1;i<=n;++i) v[i]+=v[i-1];
for (int i=cn;i>=1;--i) q[v[tr[i].len]--]=i;
for (int i=cn;i>=1;--i)
if (t==1) rght[tr[q[i]].par]+=rght[q[i]];
else rght[q[i]]=1;
rght[1]=0;
for (int i=cn;i>=1;--i){
tt=q[i];sum[tt]=rght[tt];
for (int j=0;j<C;++j)
sum[tt]+=sum[tr[tt].s[j]];
}
}
void dfs(int x,int pos){
if (k<=rght[x]) {k=0;return;}
k-=rght[x];
for (int i=0;i<C;++i)
if (tr[x].s[i]){
if (k<=sum[tr[x].s[i]]){
sc[pos]='a'+i;
dfs(tr[x].s[i],pos+1);
return;
}
k-=sum[tr[x].s[i]];
}
}
Abigail into(){
scanf("%s",c+1);
n=strlen(c+1);
scanf("%d%d",&t,&k);
}
Abigail work(){
Build_sam();
for (int i=1;i<=n;++i)
extend(c[i]-'a');
pre();
dfs(1,1);
}
Abigail outo(){
k>0?puts("-1"):printf("%s\n",sc+1);
}
int main(){
into();
work();
outo();
return 0;
}