【SAM】51NOD 1651 寻找子串

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 }
View Code

猜你喜欢

转载自www.cnblogs.com/uuuxxllj/p/10817448.html
今日推荐