SPOJ SUBLEX 求第k小子串

 题目大意:

对于一个给定字符串,找到其所有不同的子串中排第k小的子串

 

先构建后缀自动机,然后我们可以将整个后缀自动机看做是一个DAG图,那么我们先进行拓扑排序得到 *b[N]

对于每个节点记录一个sc值,表示当前节点往下走可以得到不同的字符串的个数

然后从后往前,每次到达一个节点,当前节点sc赋1,然后每个可以往下走的son节点,都把这个son上的sc加到当前节点上即可

接下来得到一个排名,从root开始走,从a~z循环,通过sc正确的找到下一个进入的节点

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 #define N 90005
 7 
 8 struct SamNode{
 9     int l , sc;
10     SamNode *son[26] , *f;
11 }sam[N<<1] , *root , *last , *b[N<<1];
12 
13 int cnt , num[N] , n , k;
14 char s[N];
15 void add(int x)
16 {
17     SamNode *p = &sam[++cnt] , *jp = last;
18     p->l = jp->l+1;
19     last = p;
20     for(; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
21     if(!jp) p->f = root;
22     else{
23         if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
24         else{
25             SamNode *r = &sam[++cnt] , *q = jp->son[x];
26             *r = *q; r->l = jp->l+1;
27             p->f = q->f = r;
28             for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x] = r;
29         }
30     }
31 }
32 
33 void build()
34 {
35     int len = strlen(s);
36     for(int i=0 ; i<len ; i++) add(s[i]-'a');
37     for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++;
38     for(int i=1 ; i<=len ; i++) num[i]+=num[i-1];
39     for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i];
40 
41     for(int i=cnt ; i>=1 ; i--){
42         b[i]->sc=1;
43         for(int j=0 ; j<26 ; j++){
44             if(b[i]->son[j])
45                 b[i]->sc+=b[i]->son[j]->sc;
46         }
47     }
48 }
49 
50 void solve()
51 {
52     scanf("%d" , &n);
53     char tmp[N];
54     int val , t;//t表示tmp中的位数
55     while(n--){
56         scanf("%d" , &k);
57         SamNode *cur = root;
58         val = 0 , t=0;
59         while(val<k){
60             for(int i=0 ; i<26 ; i++){
61                 if(cur->son[i]){
62                     if(val+cur->son[i]->sc<k) val+=cur->son[i]->sc;
63                     else{
64                         val++;
65                         tmp[t++] = i+'a';
66                         cur = cur->son[i];
67                         break;
68                     }
69                 }
70             }
71         }
72         tmp[t]='\0';
73         printf("%s\n" , tmp);
74     }
75 }
76 
77 int main()
78 {
79   //  freopen("a.in" , "r" , stdin);
80     scanf("%s" , s);
81     root = last = &sam[cnt=0];
82     build();
83     solve();
84     return 0;
85 }

 

你可能感兴趣的:(poj)