2806: [Ctsc2012]Cheat(后缀自动机+单调队列

作者: AmadeusChan | 来源:发表于2019-02-16 19:57 被阅读0次

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

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

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

#include <cstdio>
#include <algorithm>
#include <cstring>
   
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(后缀自动机+单调队列

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

  • 字符串算法小结

    hash kmp和ac自动机 后缀数组,后缀自动机,后缀树 扩展kmp manacher算法 回文自动机 可删改的...

  • 后缀自动机

  • 单调队列

    队列中各元素序列是严格单调递增或递减的,队首和队尾都可以出队,但入队只能从队尾入队。由于队列内元素有序,取最值的复...

  • 单调队列

    42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。...

  • 单调队列

    原题链接[https://www.acwing.com/problem/content/137/] 给定一个长度为...

  • 单调队列

    单调队列,也可以叫做Monotonic Queue这种数据结构主要可以优化能够用max/min heap 解决的题...

  • 单调队列&单调栈

    就是一些很神奇的数据结构 A:最大矩形 题目: 给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方...

  • 动态规划之单调队列

    单调队列的性质 单调队列中的元素单调递减或单调递增 只能在队尾插入,可以从两头删除 其目的就是为了保持队列中元素的...

  • Algorithm小白入门 -- 队列和栈

    队列和栈队列实现栈、栈实现队列单调栈单调队列运用栈去重 1. 队列实现栈、栈实现队列 队列是一种先进先出的数据结构...

网友评论

    本文标题:2806: [Ctsc2012]Cheat(后缀自动机+单调队列

    本文链接:https://www.haomeiwen.com/subject/gumieqtx.html