對於一個給定長度爲N的字符串,求它的第K小子串是什麼。node
3998: [TJOI2015]弦論
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 2627 Solved: 881Description
對於一個給定長度爲N的字符串,求它的第K小子串是什麼。node
Input
第一行是一個僅由小寫英文字母構成的字符串Sios
第二行爲兩個整數T和K,T爲0則表示不一樣位置的相同子串算做一個。T=1則表示不一樣位置的相同子串算做多個。K的意義如題所述。Output
輸出僅一行,爲一個數字串,爲第K小的子串。若是子串數目不足K個,則輸出-1數組
Sample Input
aabc
0 3Sample Output
aab
HINT
N<=5*10^5ide
T<2
K<=10^9Source
【分析】spa
建SAM,而後跑。code
right數組要按照拓撲序來求啊!!!!blog
而後累計兒子的和的時候也要用拓撲序。ip
具體拓撲序:字符串
for(int i=1;i<=tot;i++) v[t[i].step]++; for(int i=1;i<=tot;i++) v[i]+=v[i-1]; for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i;
相似後綴數組那裏的了。string
T=0,就right一開始都爲1;T=1,就用right數組。
空串算一個串,一開始k++。
固然後綴數組也是能夠的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 500010 8 9 struct node 10 { 11 int pre,last,son[30],step; 12 }t[Maxn*2]; 13 int rt[Maxn*2],sm0[2*Maxn],sm1[2*Maxn]; 14 int v[2*Maxn],q[2*Maxn]; 15 16 struct sam 17 { 18 int last,tot; 19 void extend(int k) 20 { 21 int np=++tot,p=last; 22 t[np].step=t[last].step+1; 23 rt[np]=1; 24 while(p&&!t[p].son[k]) 25 { 26 t[p].son[k]=np; 27 p=t[p].pre; 28 } 29 if(!p) t[np].pre=1; 30 else 31 { 32 int q=t[p].son[k]; 33 if(t[q].step==t[p].step+1) t[np].pre=q; 34 else 35 { 36 int nq=++tot; 37 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son)); 38 t[nq].step=t[p].step+1; 39 t[nq].pre=t[q].pre; 40 t[q].pre=t[np].pre=nq; 41 while(p&&t[p].son[k]==q) 42 { 43 t[p].son[k]=nq; 44 p=t[p].pre; 45 } 46 } 47 } 48 last=np; 49 } 50 void init() 51 { 52 for(int i=1;i<=tot;i++) v[t[i].step]++; 53 for(int i=1;i<=tot;i++) v[i]+=v[i-1]; 54 for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i; 55 56 // for(int i=1;i<=tot;i++) rt[i]=1; 57 // for(int i=tot;i>=1;i--) rt[t[i].pre]+=rt[i]; 58 // rt[1]=1; 59 for(int i=tot;i>=1;i--) 60 { 61 int nw=q[i]; 62 rt[t[nw].pre]+=rt[nw]; 63 }rt[1]=1; 64 65 for(int i=tot;i>=1;i--) 66 { 67 int nw=q[i]; 68 sm0[nw]=1;sm1[nw]=rt[nw]; 69 for(int j=1;j<=26;j++) if(t[nw].son[j]) 70 { 71 sm0[nw]+=sm0[t[nw].son[j]]; 72 sm1[nw]+=sm1[t[nw].son[j]]; 73 } 74 } 75 } 76 void ffind(int opt,int k) 77 { 78 int sm,nw=1; 79 k++; 80 while(1) 81 { 82 sm=opt?rt[nw]:1; 83 for(int i=1;i<=26;i++) if(t[nw].son[i]) 84 { 85 int ss=sm; 86 if(!opt) sm+=sm0[t[nw].son[i]]; 87 else sm+=sm1[t[nw].son[i]]; 88 if(sm>=k) {k-=ss;printf("%c",'a'+i-1);nw=t[nw].son[i];break;} 89 } 90 if(!opt&&k==1) break; 91 if(opt&&k<=rt[nw]) break; 92 } 93 printf("\n"); 94 } 95 }sam; 96 97 char s[Maxn]; 98 99 int main() 100 { 101 scanf("%s",s); 102 int l=strlen(s); 103 sam.last=sam.tot=1; 104 for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1); 105 sam.init(); 106 int opt,k; 107 scanf("%d%d",&opt,&k); 108 if(!opt&&k+1>sm0[1]) printf("-1\n"); 109 else if(opt&&k+rt[1]>sm1[1]) printf("-1\n"); 110 else sam.ffind(opt,k); 111 return 0; 112 }
2017-04-17 13:59:36