SAM
寻找本质相同的第k小子串
sz[]代表endpos集合
sum[]表示经过该节点的子串数
那么可以贪心地从字典序小的节点往字典序大的节点方向转移
1 #include <bits/stdc++.h> 2 #define For(i,a,b) for(int i=a;i<=b;++i) 3 #define Dec(i,b,a) for(int i=b;i>=a;--i) 4 #define file() freopen("c://users/asus/desktop/v.txt","r",stdin) 5 #define inf 0x3f3f3f3f 6 using namespace std; 7 8 typedef unsigned long long ll; 9 inline ll qr(){ 10 ll x=0,f=1; char ch=getchar(); 11 while(!isdigit(ch)){if(ch=='-')f=-1; ch=getchar();} 12 while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48); ch=getchar();} 13 return x*f; 14 } 15 const int N = 200010; 16 char s[N]; 17 int f[N],l[N],sz[N],c[N][26]; 18 ll sum[N]; 19 int ct,last,a[N],b[N],n,k; 20 void ext(int v) 21 { 22 int p=last,np=++ct; l[np]=l[p]+1; sz[np]=1; last=np; 23 for(;p&&!c[p][v];p=f[p]) c[p][v]=np; 24 if(!p) f[np]=1; 25 else 26 { 27 int q=c[p][v]; 28 if(l[q]==l[p]+1) f[np]=q; 29 else 30 { 31 int nq=++ct; l[nq]=l[p]+1; 32 memcpy(c[nq],c[q],sizeof c[q]); 33 f[nq]=f[q]; f[q]=f[np]=nq; 34 for(;q==c[p][v];p=f[p]) c[p][v]=nq; 35 } 36 } 37 } 38 int main() 39 { 40 // file(); 41 scanf("%s%d",s+1,&k); 42 n=strlen(s+1); 43 if(1LL*n*(n+1)/2<k) return puts("No such line."),0; 44 ct=last=1; 45 For(i,1,n) ext(s[i]-'a'); 46 For(i,1,ct) b[l[i]]++; 47 For(i,1,n) b[i]+=b[i-1]; 48 For(i,1,ct) a[b[l[i]]--]=i; 49 Dec(i,ct,1) sz[f[a[i]]]+=sz[a[i]]; 50 For(i,1,ct) sum[i]=sz[i]; 51 sum[1]=sz[1]=0; 52 Dec(i,ct,1) For(j,0,25) if(c[a[i]][j]) sum[a[i]]+=sum[c[a[i]][j]]; 53 int u=1,v; 54 for(;k>0;k-=sz[u]) 55 { 56 v=0; 57 while(k>sum[c[u][v]]) k-=sum[c[u][v]],v++; 58 u=c[u][v]; 59 putchar('a'+v); 60 } 61 return 0; 62 }