码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3998 [TJOI2015]弦论

时间:2017-10-06 13:53:52      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:register   数字   一个   第k小   tput   log   scanf   rip   void   

Description

对于一个给定长度为N的字符串,求它的第K小子串是什么。

Input

第一行是一个仅由小写英文字母构成的字符串S

第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

Output

输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

Sample Input

aabc
0 3

Sample Output

aab

HINT 

N<=5*10^5

T<2
K<=10^9

 

正解:后缀自动机。

我们可以使用后缀自动机来求出每一个后缀,那么可以知道,一个字符串的出现次数就是它的$right$集合大小,也就是它在后缀自动机的$parent$树上的子树大小。

那么如果$T=1$,就把一个点的$sz$统计成它的$parent$子树,否则它的$sz$就是$1$,然后我们贪心地找出第$k$小子串就行了。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define N (1000010)
 6 
 7 using namespace std;
 8 
 9 int ch[N][26],l[N],fa[N],sz[N],sum[N],c[N],id[N],n,t,k,la,tot,len;
10 char s[N];
11 
12 il void add(RG int c){
13   RG int p=la,np=++tot; la=np,l[np]=l[p]+1,sz[np]=1;
14   for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
15   if (!p){ fa[np]=1; return; } RG int q=ch[p][c];
16   if (l[q]==l[p]+1) fa[np]=q; else{
17     RG int nq=++tot; l[nq]=l[p]+1;
18     fa[nq]=fa[q],fa[q]=fa[np]=nq;
19     memcpy(ch[nq],ch[q],sizeof(ch[q]));
20     for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
21   }
22   return;
23 }
24 
25 il void dfs(RG int x,RG int k){
26   if (k<=sz[x]) return; RG int c=sz[x];
27   for (RG int i=0;i<26;++i)
28     if (k<=c+sum[ch[x][i]]){
29       putchar(a+i);
30       return dfs(ch[x][i],k-c);
31     } else c+=sum[ch[x][i]];
32   return;
33 }
34 
35 int main(){
36 #ifndef ONLINE_JUDGE
37   freopen("kth.in","r",stdin);
38   freopen("kth.out","w",stdout);
39 #endif
40   scanf("%s",s+1),len=strlen(s+1),cin>>t>>k,tot=la=1;
41   for (RG int i=1;i<=len;++i) add(s[i]-a);
42   for (RG int i=1;i<=tot;++i) ++c[l[i]];
43   for (RG int i=1;i<=tot;++i) c[i]+=c[i-1];
44   for (RG int i=1;i<=tot;++i) id[c[l[i]]--]=i;
45   if (t) for (RG int i=tot;i;--i) sz[fa[id[i]]]+=sz[id[i]];
46   else for (RG int i=tot;i;--i) sz[id[i]]=1; sz[1]=0;
47   for (RG int i=tot;i;--i){
48     sum[id[i]]=sz[id[i]];
49     for (RG int j=0;j<26;++j)
50       sum[id[i]]+=sum[ch[id[i]][j]];
51   }
52   if (sum[1]<k) puts("-1"); else dfs(1,k); return 0;
53 }

 

bzoj3998 [TJOI2015]弦论

标签:register   数字   一个   第k小   tput   log   scanf   rip   void   

原文地址:http://www.cnblogs.com/wfj2048/p/7630221.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!