2806: [Ctsc2012]Cheat(后缀自动机+单调队列优化动态规划+二分查找)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2806

第一道后缀自动机额。。。SAM预处理,二分L,然后DP判定,用单调队列优化。

代码(PS:好像网上很多代码都是有问题的,就是答案为1时会输出2。。。):

#include 
#include 
#include 
   
using namespace std ;
   
#define rep( i , x ) for ( int i = 0 ; i ++ < x ; )
   
#define C( t , x ) sam[ t ].child[ x ]
#define P( t ) sam[ t ].parent
#define L( t ) sam[ t ].len 
#define N( t ) sam[ t ]
   
#define inf 0x7fffffff
#define maxn 1200010
#define maxv ( maxn << 1 )
   
#define check( ch ) ( ch == '0' || ch == '1' )
  
#define G( x ) ( f[ x ] - x )
   
struct node {
    int child[ 3 ] , parent , len ; 
    node(  ) {
        parent = len = 0 ; 
        memset( child , 0 , sizeof( child ) ) ;
    }
} sam[ maxv ] ;
   
int root , last , V ;
   
void Init_sam(  ) {
    root = last = maxv - 1 , V = 0 ;
}
   
void add_sam( int ch , int l ) {
    int p = last , np = ++ V ;
    L( V ) = l ;
    for ( ; p && ! C( p , ch ) ; p = P( p ) ) C( p , ch ) = np ;
    if ( ! p ) P( np ) = root ; else {
        if ( L( C( p , ch ) ) == L( p ) + 1 ) P( np ) = C( p , ch ) ; else {
            int q = C( p , ch ) , r = ++ V ;
            N( r ) = N( q ) ;
            L( r ) = L( p ) + 1 ; 
            P( q ) = P( np ) = r ; 
            for ( ; p && C( p , ch ) == q ; p = P( p ) ) C( p , ch ) = r ; 
        }
    }
    last = np ; 
}
   
int n , m , s[ maxn ] , Len , cnt = 0 ; 
   
void getstr(  ) {
    Len = 0 ; 
    int ch ; 
    for ( ch = getchar(  ) ; ! check( ch ) ; ch = getchar(  ) ) ;
    s[ ++ Len ] = ch - '0' ;
    for ( ch = getchar(  ) ; check( ch ) ; ch = getchar(  ) ) {
        s[ ++ Len ] = ch - '0' ;
    }
}
   
int f[ maxn ] , que[ maxn ] , head , tail , d[ maxn ] ;
  
bool Dp( int L ) {
    head = 1 , tail = 0 ;
    f[ 0 ] = 0 ;
    int temp = 0 ;
    rep( i , Len ) {
        f[ i ] = f[ i - 1 ] ;
        if ( i - L >= 0 ) {
            int x = i - L ;
            for ( ; head <= tail && G( que[ tail ] ) <= G( x ) ; -- tail ) ;
            que[ ++ tail ] = x ;
        }
        for ( ; head <= tail && que[ head ] < i - d[ i ] ; ++ head ) ;
        if ( head <= tail ) {
            f[ i ] = max( f[ i ] , G( que[ head ] ) + i ) ;
        }
        temp = max( temp , f[ i ] ) ;
    }
    return 10 * temp >= 9 * Len ;
}
  
int Solve(  ) {
    for ( int t = root , i = 0 , temp = 0 ; i ++ < Len ; ) {
        if ( C( t , s[ i ] ) ) ++ temp , t = C( t , s[ i ] ) ; else {
            for ( ; t && ! C( t , s[ i ] ) ; t = P( t ) ) ;
            if ( ! t ) t = root , temp = 0 ; else {
                temp = L( t ) + 1 ;
                t = C( t , s[ i ] ) ;
            }
        }
        d[ i ] = temp ;
    }
    int l = 0 , r = Len + 1 ;
    while ( r - l > 1 ) {
        int mid = ( l + r ) >> 1 ; 
        if ( Dp( mid ) ) l = mid ; else r = mid ;
    }
    return l ; 
}
   
int main(  ) {
    Init_sam(  ) ;
    scanf( "%d%d" , &n , &m ) ;
    rep( i , m ) {
        getstr(  ) ;
        rep( j , Len ) add_sam( s[ j ] , ++ cnt ) ;
        add_sam( 2 , ++ cnt ) ;
    }
    while ( n -- ) {
        getstr(  ) ; 
        printf( "%d\n" , Solve(  ) ) ;
    }
    return 0 ;
}

你可能感兴趣的:(2806: [Ctsc2012]Cheat(后缀自动机+单调队列优化动态规划+二分查找))