bzoj3998 [TJOI2015]弦论

地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3998

题面:

3998: [TJOI2015]弦论

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 3127  Solved: 1079

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
 
思路:  
  对于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 }

 

posted @ 2017-09-14 20:03  weeping  阅读(222)  评论(0编辑  收藏  举报