zoukankan      html  css  js  c++  java
  • 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, "
    " );
     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
    " );
    107         return;
    108     }
    109     int u = 0;
    110     int kth = k;
    111     while(1) {
    112         if( kth<=rsiz[u] ) {
    113             printf( "
    " );
    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
  • 相关阅读:
    C语言I博客作业09
    C语言I博客作业08
    第十四周助教总结
    C语言I博客作业07
    第十三周助教总结
    C语言I博客作业06
    第十二周助教总结
    学期总结
    C语言I博客作业09
    C语言I博客作业08
  • 原文地址:https://www.cnblogs.com/idy002/p/4516574.html
Copyright © 2011-2022 走看看