spoj Lexicographical Substring Search
Little Daniel loves to play with strings! He always finds different ways to have fun with strings! Knowing that, his friend Kinan decided to test his skills so he gave him a string S and asked him Q questions of the form:
If all distinct substrings of string S were sorted lexicographically, which one will be the K-th smallest?
After knowing the huge number of questions Kinan will ask, Daniel figured out that he can't do this alone. Daniel, of course, knows your exceptional programming skills, so he asked you to write him a program which given S will answer Kinan's questions.
Example:
S = "aaa" (without quotes)
substrings of S are "a" , "a" , "a" , "aa" , "aa" , "aaa". The sorted list of substrings will be:
"a", "aa", "aaa".
Input
In the first line there is Kinan's string S (with length no more than 90000 characters). It contains only small letters of English alphabet. The second line contains a single integer Q (Q <= 500) , the number of questions Daniel will be asked. In the next Q lines a single integer K is given (0 < K < 2^31).
Output
Output consists of Q lines, the i-th contains a string which is the answer to the i-th asked question.
Example
Input:
aaa
2
2
3
Output: aa
aaa
Edited: Some input file contains garbage at the end. Do not process them.
题目大意:找字典序第k大的子串,我们可以用后缀数组或者后缀自动机直接做。
但是这里我用的是一种借助于二分的做法。
实际上考虑 parent 可以进一步优化算法的复杂度,考虑原先的 parent 树一个节点代表的多个串都是最长的串的一个后缀,是一棵类似于前缀树的结构,这样不能适用于一些字典序上优美的性质。不妨将串反序插入到sam 中,这样每一个点能代表的多个串都是最长的串的前缀,这些串从长到短在字典序上一定是有序的。扩展到整棵树上,根据 mn(u)=len(fa(u))+1 ,每个点代表的字符串都比其祖先代表的字符串的字典序大。于是可以计算出每一棵子树代表了多少串,在 dfn 序上二分答案即可,复杂度是 O(qlogn)。( 由于输出还是最多要n的,所以还是qn)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 int const N=90000+10; 5 struct node{ 6 int len,fa,ch[26]; 7 }a[N<<1]; 8 int tot,ls,w[N<<1],num[N],sa[N<<1],e[N<<1][26],pos[N<<1],cnt; 9 char s[N]; 10 ll sum[N<<1]; 11 void add(int c,int id){ 12 int p=ls; 13 int np=ls=++tot; 14 a[np].len=a[p].len+1; 15 w[np]=id; 16 for(;p&& !a[p].ch[c]; p=a[p].fa) a[p].ch[c]=np; 17 if(!p) a[np].fa=1; 18 else { 19 int q=a[p].ch[c]; 20 if(a[q].len==a[p].len+1) a[np].fa=q; 21 else { 22 int nq=++tot; 23 a[nq]=a[q]; 24 a[nq].len=a[p].len+1; 25 a[q].fa=a[np].fa=nq; 26 for(;p&&a[p].ch[c]==q;p=a[p].fa) 27 a[p].ch[c]=nq; 28 } 29 } 30 } 31 void dfs(int x){ 32 if(!x) return; 33 pos[++cnt]=x; 34 for(int i=0;i<26;i++) 35 dfs(e[x][i]); 36 } 37 int main(){ 38 scanf("%s",s); 39 tot=ls=1; 40 int len=strlen(s); 41 for(int i=len-1;i>=0;i--) 42 add(s[i]-'a',i+1); 43 for(int i=1;i<=tot;i++) num[a[i].len]++; 44 for(int i=1;i<=len;i++) num[i]+=num[i-1]; 45 for(int i=1;i<=tot;i++) sa[num[a[i].len]--]=i; 46 for(int i=tot;i>=1;i--) { 47 int x=sa[i]; 48 int f=a[x].fa; 49 w[f]=w[f]? w[f]: w[x]; 50 } 51 for(int i=2;i<=tot;i++){ 52 int f=a[i].fa; 53 int c=s[w[i]+a[f].len-1]-'a'; 54 e[f][c]=i; 55 } 56 dfs(1); 57 for(int i=2;i<=tot;i++){ 58 int t=pos[i]; 59 int f=a[t].fa; 60 int tmp=a[t].len-a[f].len; 61 sum[i]=sum[i-1]+tmp; 62 } 63 int q; 64 scanf("%d",&q); 65 while (q--){ 66 int k; 67 scanf("%d",&k); 68 int t=lower_bound(sum+1,sum+tot+1,k)-sum; 69 k-=sum[t-1]; 70 t=pos[t]; 71 int f=a[t].fa; 72 int len=a[f].len+k; 73 for(int i=w[t];i<w[t]+len;i++) 74 putchar(s[i-1]); 75 putchar('\n'); 76 } 77 return 0; 78 }