bzoj3998 [TJOI2015]弦论
地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3998
题面:
3998: [TJOI2015]弦论
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 3127 Solved: 1079
Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。
Input
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
Sample Input
aabc
0 3
0 3
Sample Output
aab
HINT
N<=5*10^5
T<2
K<=10^9
思路:
对于t=1的情况,把每个状态的cnt记为1.
t=0时,把cnt记为endpos集合的大小。
然后dp即可。
1 /************************************************************** 2 Problem: 3998 3 User: weeping 4 Language: C++ 5 Result: Accepted 6 Time:6736 ms 7 Memory:122876 kb 8 ****************************************************************/ 9 10 #include <bits/stdc++.h> 11 12 using namespace std; 13 14 15 16 struct SAM 17 { 18 static const int MAXN = 500002<<1;//大小为字符串长度两倍 19 static const int LetterSize = 26; 20 21 int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN]; 22 int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组 23 24 void init( void) 25 { 26 last = tot = 1; 27 len[1] = 0; 28 memset(ch,0,sizeof ch); 29 memset(fa,0,sizeof fa); 30 memset(cnt,0,sizeof cnt); 31 } 32 33 void add( int x) 34 { 35 int p = last, np = last = ++tot; 36 len[np] = len[p] + 1, cnt[last] = 1; 37 while( p && !ch[p][x]) ch[p][x] = np, p = fa[p]; 38 if( p == 0) 39 fa[np] = 1; 40 else 41 { 42 int q = ch[p][x]; 43 if( len[q] == len[p] + 1) 44 fa[np] = q; 45 else 46 { 47 int nq = ++tot; 48 memcpy( ch[nq], ch[q], sizeof ch[q]); 49 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq; 50 while( p && ch[p][x] == q) ch[p][x] = nq, p = fa[p]; 51 } 52 } 53 } 54 55 void toposort( void) 56 { 57 for(int i = 1; i <= len[last]; i++) sum[i] = 0; 58 for(int i = 1; i <= tot; i++) sum[len[i]]++; 59 for(int i = 1; i <= len[last]; i++) sum[i] += sum[i-1]; 60 for(int i = 1; i <= tot; i++) tp[sum[len[i]]--] = i; 61 for(int i = tot; i; i--) cnt[fa[tp[i]]] += cnt[tp[i]]; 62 } 63 64 void solve( int t, int k) 65 { 66 for(int i = 1; i <= len[last]; i++) sum[i] = 0; 67 for(int i = 1; i <= tot; i++) sum[len[i]]++; 68 for(int i = 1; i <= len[last]; i++) sum[i] += sum[i-1]; 69 for(int i = 1; i <= tot; i++) tp[sum[len[i]]--] = i; 70 for(int i = tot; i; i--) 71 if(t) cnt[fa[tp[i]]] += cnt[tp[i]]; 72 else cnt[i] = 1; 73 cnt[1]=0; 74 for(int i = 1; i <= tot; i++) sum[i] = cnt[i]; 75 for(int i = tot; i; i--) 76 for(int j = 0; j < 26; j++) 77 sum[tp[i]] += sum[ch[tp[i]][j]]; 78 if(sum[1]<k) {printf("-1\n");return;} 79 int p=1; 80 while(k>0) 81 { 82 for(int j = 0; j < 26; j++) 83 if(sum[ch[p][j]]>=k) 84 { 85 printf("%c",'a'+j),p=ch[p][j],k-=cnt[p]; 86 break; 87 } 88 else 89 k-=sum[ch[p][j]]; 90 } 91 } 92 } sam; 93 94 char ss[500004]; 95 96 int main(void) 97 { 98 int t,k; 99 //freopen("in.acm","r",stdin); 100 sam.init(); 101 scanf("%s%d%d",ss,&t,&k); 102 for(int i=0,len=strlen(ss);i<len;i++) sam.add(ss[i]-'a'); 103 sam.solve(t,k); 104 return 0; 105 }
作者:weeping
出处:www.cnblogs.com/weeping/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。