Luogu P3975 [TJOI2015]弦论
本质不同的第 \(k\) 小:每个点的初始权值为 \(1\) 。
只区分位置的第 \(k\) 小:每个点的初始权值为 \(|{\rm endpos}|\) ,表示出现的次数。
然后进行拓扑排序。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=1000010;
int n,t,k,lst=1,tot=1,cnt;
int len[N],fa[N],c[N][26],sz[N],d[N],mem[N],f[N];
char s[N>>1];
int vr[N<<1],nxt[N<<1],fir[N];
inline void add(int u,int v)
{vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void add(int ch) {
R p=lst,np=lst=++tot;
sz[tot]=1;
len[np]=len[p]+1;
for(;p&&!c[p][ch];p=fa[p]) c[p][ch]=np;
if(!p) fa[np]=1;
else {
R q=c[p][ch];
if(len[q]==len[p]+1) fa[np]=q;
else {
R nq=++tot;
memcpy(c[nq],c[q],26<<2);
fa[nq]=fa[q],len[nq]=len[p]+1;
fa[np]=fa[q]=nq;
for(;p&&c[p][ch]==q;p=fa[p]) c[p][ch]=nq;
}
}
}
inline void solve() {
R p=1;
while(k) {
for(R i=0;i<26;++i) if(c[p][i]) {
if(k>f[c[p][i]]) k-=f[c[p][i]];
else {
putchar(i+'a');
p=c[p][i];
k-=sz[p]; break;
}
}
} putchar(10);
}
inline void main() {
scanf("%s",s+1);
t=g(),k=g(),n=strlen(s+1);
for(R i=1;i<=n;++i) add(s[i]-'a');
for(R i=1;i<=tot;++i) ++d[len[i]];
for(R i=1;i<=n;++i) d[i]+=d[i-1];
for(R i=1;i<=tot;++i) mem[d[len[i]]--]=i;
if(!t) for(R i=1;i<=tot;++i) sz[i]=1;
else for(R i=tot;i;--i)
sz[fa[mem[i]]]+=sz[mem[i]];;
//sz[u]是
//t==0: 1,表示每个点初始有个空串。
//t==1: parent树的子树和,即 |endpos|
//f[u]是
//t==0: 子串个数
//t==1: \sum 每个串的出现次数(相当于是带权的)
sz[1]=0;
for(R i=tot;i;--i) {
R u=mem[i];
f[u]=sz[u];
for(R j=0;j<26;++j) if(c[u][j])
f[u]+=f[c[u][j]];
}
if(k>f[1]) puts("-1");
else solve();
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.09