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 }
View Code

 

posted @ 2015-05-20 10:48  idy002  阅读(446)  评论(0编辑  收藏  举报