bzoj 2998 第k小字串
这道题用后缀数组貌似会T。
后缀自动机做法:
t==0:第k小的本质不同字串
首先把后缀自动机建出来,我们会得到一个DAG,并且只存在一个点入度为0(我们称之为根),可以证明字符串的任意一个本质不同的子串(不包括空串)与该自动机上一条起点为根的长度(路径边数)大于0的路径一一对应。所以我们就可以进行DP了,dp[u]表示以u为起点的串的个数,然后有点像在BST中找第k小的思想。
t==1:第k小的普通字串(不同位置但本质相同的要区分)
还是要dp,我yy的一个状态含义是:dp[u]表示,u节点的对应的后缀(right集合中每个位置对应一个后缀)的所有前缀的个数(空串也是前缀,并且不同位置的空串相互区分)。
这样,我们就默认一个长度为n的字符串有(n+1)*(n+2)/2个子串(包括n+1个空串)。
1 /************************************************************** 2 Problem: 3998 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:9736 ms 7 Memory:134596 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #define N 1000010 13 14 typedef long long dnt; 15 16 int n, k, t; 17 int son[N][26], val[N], pnt[N], rsiz[N], ntot, last; 18 int idgr[N], stk[N], qu[N], bg, ed, top; 19 dnt dp[N]; 20 char str[N]; 21 22 void init() { 23 ntot = 0; 24 pnt[0] = -1; 25 } 26 void append( int c ) { 27 int p = last; 28 int np = ++ntot; 29 val[np] = val[last]+1; 30 while( ~p && !son[p][c] ) 31 son[p][c]=np,p=pnt[p]; 32 if( p==-1 ) { 33 pnt[np] = 0; 34 } else { 35 int q = son[p][c]; 36 if( val[q]==val[p]+1 ) { 37 pnt[np] = q; 38 } else { 39 int nq = ++ntot; 40 memcpy( son[nq], son[q], sizeof(son[nq]) ); 41 val[nq] = val[p]+1; 42 rsiz[nq] = rsiz[q]; 43 pnt[nq] = pnt[q]; 44 pnt[q] = pnt[np] = nq; 45 while( ~p && son[p][c]==q ) son[p][c]=nq,p=pnt[p]; 46 } 47 } 48 last = np; 49 while( ~np ) { 50 rsiz[np]++; 51 np = pnt[np]; 52 } 53 } 54 void print() { 55 for( int u=0; u<=ntot; u++ ) { 56 fprintf( stderr, "%d(dp[%d]=%lld rsiz[%d]=%d): ", u, u, dp[u], u, rsiz[u] ); 57 for( int c=0; c<26; c++ ) { 58 int v=son[u][c]; 59 if( !v ) continue; 60 fprintf( stderr, "%c,%d ", c+'a', v ); 61 } 62 fprintf( stderr, "\n" ); 63 } 64 } 65 void make_topo() { 66 for( int u=0; u<=ntot; u++ ) { 67 for( int c=0; c<26; c++ ) { 68 int v=son[u][c]; 69 if( !v ) continue; 70 idgr[v]++; 71 } 72 } 73 top = 0; 74 for( int u=0; u<=ntot; u++ ) 75 if( idgr[u]==0 ) 76 stk[++top] = u; 77 bg = 1, ed = 0; 78 while( top ) { 79 int u=stk[top--]; 80 qu[++ed] = u; 81 for( int c=0; c<26; c++ ) { 82 int v=son[u][c]; 83 if( !v ) continue; 84 idgr[v]--; 85 if( idgr[v]==0 ) 86 stk[++top] = v; 87 } 88 } 89 } 90 void dodp( int s ) { 91 make_topo(); 92 rsiz[s] = 0; 93 if( t==0 ) 94 for( int i=2; i<=ed; i++ ) 95 rsiz[qu[i]] = 1; 96 for( int i=ed; i>=1; i-- ) { 97 int u=qu[i]; 98 dp[u] = rsiz[u]; 99 for( int c=0; c<26; c++ ) { 100 int v=son[u][c]; 101 if( !v ) continue; 102 dp[u] += dp[v]; 103 } 104 } 105 if( dp[0]<k ) { 106 printf( "-1\n" ); 107 return; 108 } 109 int u = 0; 110 int kth = k; 111 while(1) { 112 if( kth<=rsiz[u] ) { 113 printf( "\n" ); 114 return; 115 } else kth-=rsiz[u]; 116 for( int c=0; c<26; c++ ) { 117 int v=son[u][c]; 118 if( !v ) continue; 119 if( dp[v]>=kth ) { 120 u = v; 121 printf( "%c", c+'a' ); 122 break; 123 } else { 124 kth -= dp[v]; 125 } 126 } 127 } 128 } 129 int main() { 130 scanf( "%s", str ); 131 scanf( "%d%d", &t, &k ); 132 init(); 133 for( int i=0; str[i]; i++ ) 134 append( str[i]-'a' ); 135 dodp(0); 136 // print(); 137 }