链接:#2102. 「TJOI2015」弦论 - 题目 - LibreOJ (loj.ac)
题意:对于一个给定长度为 N 的字符串,求它的第 K 小子串。
字典序第k大子串:对应SAM中字典序第k大的路径
代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+8;
int n;
string s;
int t,k;
struct Node
{
int len,link;
int ch[26];
Node(){
memset(ch,0,sizeof(ch));
len=link=0;
}
}node[N];
struct Edge{
int to,next;
}e[N];
int head[N],cnt=0;
void add(int x,int y){
e[++cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt;
}
int tot=1,las=1;
int zhi[N];
void addnode(int c){
register int p=las,cur=las=++tot;zhi[tot]=1;
node[cur].len=node[p].len+1;
for(;p&&!node[p].ch[c];p=node[p].link){
node[p].ch[c]=cur;
}
if(!p) node[cur].link=1;
else{
register int q=node[p].ch[c];
if(node[q].len==node[p].len+1){
node[cur].link=q;
}
else{
register int clone=++tot;
node[clone]=node[q];
node[clone].len=node[p].len+1;
node[cur].link=node[q].link=clone;
for(;p&&node[p].ch[c]==q;p=node[p].link){
node[p].ch[c]=clone;
}
}
}
}
void dfs(int now){
for(int i=head[now];i;i=e[i].next){
dfs(e[i].to);
zhi[now]+=zhi[e[i].to];
}
}
int y[N],v[N];
void dfs2(int now){
if(v[now]) return;
v[now]=1;
for(int i=0;i<26;i++){
if(node[now].ch[i]){
dfs2(node[now].ch[i]);
y[now]+=y[node[now].ch[i]];
}
}
}
void print(int x,int k){
if(k<=zhi[x]){
return;
}
else k-=zhi[x];
for(int i=0;i<26;i++){
if(node[x].ch[i]){
if(k<=y[node[x].ch[i]]){
cout<<(char)(i+'a');
print(node[x].ch[i],k);
return;
}
else{
k-=y[node[x].ch[i]];
}
}
}
}
void solve(){
cin>>s;
s=" "+s;
cin>>t>>k;
for(int i=1;i<s.length();i++){
addnode(s[i]-'a');
}
for(int i=2;i<=tot;i++){
add(node[i].link,i);
}
dfs(1);
for(int i=1;i<=tot;i++){
if(t){
y[i]=zhi[i];
}
else y[i]=zhi[i]=1;
}
zhi[1]=y[1]=0;
dfs2(1);
if(k>y[1]){
cout<<-1<<endl;
}
else{
print(1,k);
}
//cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}