bzoj3998 [TJOI2015]弦论

题目大意:

求第k小的子串。

解题方法:

首先构建后缀自动机,通过拓扑排序求出每个子串的cnt(即该串的出现次数)。然后跑DFS,类似于平衡树求rank为k的数是什么的操作,如果当前指向的儿子(假装他是儿子)的cnt小于k,则k-=cnt,并转向下一个儿子。

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<iostream>
 7 #include<queue>
 8 #define ll long long
 9 #define del(a,b) memset(a,b,sizeof(a))
10 using namespace std;
11 const int MAXN=1e6+10;
12 int op;
13 int c[MAXN],a[MAXN];
14 char s[MAXN];
15 struct SAM
16 {
17     struct State
18     {
19         int ch[26],fa,val;
20     }t[MAXN];
21     int n,sz,root,last;
22     int cnt[MAXN],sum[MAXN];
23     int nw(int x){t[++sz].val=x;return sz;}
24     void init()
25     {
26         sz=0;root=last=nw(0);
27         del(cnt,0);del(sum,0);
28     }
29     void extend(int c)
30     {
31         int p=last,np=nw(t[p].val+1);
32         for(;p&&!t[p].ch[c];p=t[p].fa) t[p].ch[c]=np;
33         if(!p) t[np].fa=root;
34         else
35         {
36             int q=t[p].ch[c];
37             if(t[q].val==t[p].val+1) t[np].fa=q;
38             else
39             {
40                 int nq=nw(t[p].val+1);
41                 memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));
42                 t[nq].fa=t[q].fa;
43                 t[q].fa=t[np].fa=nq;
44                 for(;p&&t[p].ch[c]==q;p=t[p].fa) t[p].ch[c]=nq;
45             }
46         }
47         cnt[np]=1;last=np;
48     }
49     void RadixSort()
50     {
51         del(c,0);
52         for(int i=1;i<=sz;i++) c[t[i].val]++;
53         for(int i=1;i<=n;i++) c[i]+=c[i-1];
54         for(int i=sz;i>=1;i--) a[c[t[i].val]--]=i;
55     }
56     void get_pre()
57     {
58         for(int i=sz;i>=1;i--)
59         if(op==1) cnt[t[a[i]].fa]+=cnt[a[i]];
60         else cnt[a[i]]=1;
61         cnt[1]=0;
62         for(int i=sz;i>=1;i--)
63         {
64             sum[a[i]]=cnt[a[i]];
65             for(int j=0;j<26;j++) sum[a[i]]+=sum[t[a[i]].ch[j]];
66         }
67     }
68     void DFS(int x,int k)
69     {
70         if(k<=cnt[x]) return;
71         k-=cnt[x];
72         for(int i=0;i<26;i++)
73         if(int to=t[x].ch[i])
74         {
75             if(k<=sum[to])
76             {
77                 putchar(i+'a');
78                 DFS(to,k);return;
79             }
80             k-=sum[to];
81         }
82     }
83 }sam;
84 int main()
85 {
86     int k;sam.init();
87     scanf("%s",s+1);
88     sam.n=strlen(s+1);
89     scanf("%d%d",&op,&k);
90     for(int i=1;i<=sam.n;i++) sam.extend(s[i]-'a');
91     sam.RadixSort();sam.get_pre();
92     if(k>sam.sum[1]) puts("-1");
93     else sam.DFS(1,k);
94     return 0;
95 }

 

posted @ 2018-09-21 17:34  Oracle_LinJH  阅读(109)  评论(2编辑  收藏  举报