题目描述
为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?
输入格式
第一行是一个仅由小写英文字母构成的字符串s
第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。
输出格式
输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。
学习了后缀自动机 也终于A了这道感觉很麻烦的题= = 写个博客庆祝一下
求第k小串的套路就像是在主席树上面查询第k小数,首先用后缀自动机处理出每个节点后续的子串的个数,然后对于每个节点枚举26条边转移即可 一个节点所表示的串的出现次数即为endpos集合的size,若对于t = 1相同子串不同位置算不同子串(除复制节点外,其他节点初始|endpos|大小设置为1) 需要在后缀树上面拓扑dp t = 0的话 每个节点只表示它的最长串 所以每个节点的值为1
#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
#define Sheryang main
typedef long long ll;
#define HEAP(...) priority_queue<__VA_ARGS__ >
#define heap(...) priority_queue<__VA_ARGS__,vector<__VA_ARGS__ >,greater<__VA_ARGS__ > >
template<class T> inline T min(T &x,const T &y){return x>y?y:x;}
template<class T> inline T max(T &x,const T &y){return x<y?y:x;}
//#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
const int maxn = 1e6+7;
const int mod = 1e9+7;
/** keep hungry and keep calm! **/
int nxt[maxn],head[maxn],to[maxn],cnt;
void add(int u,int v){
nxt[++cnt] = head[u];
head[u] = cnt;
to[cnt] = v;
}
struct Sam{
int trans[maxn][26],fail[maxn];
int maxlen[maxn],minlen[maxn];
int sz,last,vis[maxn];
ll sum[maxn],num[maxn];
Sam(){
sz = last = 1;
}
void ins(int id){
int cur = ++sz,p = last;
num[cur] = 1;
maxlen[cur] = maxlen[last] + 1;
while(p && trans[p][id] == 0){
trans[p][id] = cur;
p = fail[p];
}
if(p == 0){
fail[cur] = 1;
}else{
int q = trans[p][id];
if(maxlen[q] == maxlen[p] + 1){
fail[cur] = q;
}else{
int clone = ++sz;
memcpy(trans[clone],trans[q],sizeof trans[q]);
fail[clone] = fail[q];
fail[cur] = fail[q] = clone;
maxlen[clone] = maxlen[p] + 1;
while(trans[p][id] == q){
trans[p][id] = clone;
p = fail[p];
}
}
}
last = cur;
}
void init(){
for(int i=1;i<=sz;i++) head[i] = -1;
for(int i=2;i<=sz;i++){
add(fail[i],i);
}
}
void dfs(int u){
for(int i=head[u];~i;i = nxt[i]){
dfs(to[i]);
num[u] += num[to[i]];
}
}
void calc(int u){
sum[u] = num[u];
vis[u] = 1;
for(int i=0;i<26;i++){
int v = trans[u][i];
if(v != 0){
if(vis[v] == 0)calc(v);
sum[u] += sum[v];
}
}
}
void Fuck(int u,int k){
int rt = 1;
while(k){
for(int i=0;i<26;i++){
int v = trans[rt][i];
if(v != 0){
if(k <= sum[v]){
putchar('a' + i);
k -= num[v];
rt = v;
break;
}else{
k -= sum[v];
}
}
}
}
}
void Solve(){
int op = read , k = read;
init();
if(op == 1){
dfs(1);
}else{
for(int i=1;i<=sz;i++) num[i] = 1;
}
num[1] = 0;
calc(1);
if(k > sum[1]){
printf("-1");
}else{
Fuck(1,k);
}
puts("");
}
}Sam;
char s[maxn];
int Sheryang(){
scanf("%s",s);
for(int i=0;s[i];i++){
Sam.ins(s[i]-'a');
}
Sam.Solve();
return 0;
}