pku1743 Musical Theme

 

     若在假设重复子串的长度最多为L的限制下有解, 则对于任意一个比L小的限制L'<L, 也一定有解. 这就说明存在解的连续性, 这样就可以用二分查找答案长度L.

     给出一个关于LCP的定理LCP(SA[i], SA[j]) = RMQ(Height[i+1..j]). 由此, 若存在k, 满足Height[k] < L, 则对于所有i, j 满足i < k < j, 有LCP(SA[i], SA[j]) < L. 即公共长度至少为L的两个后缀, 不会跨过一个小于L的Height低谷k, 所以我们可以得到一些由这些低谷划分开的连续的.

     在某段内, 若存在i, j 满足SA[i]+L<SA[j], 则存在一个长度至少为L的2个相同不交迭子串. 实现时只要记录在每段内, 最大和最小的SA值即可.

                                                                               --Amber大牛,《男人不容易系列Solution》

     最终还是用了大牛的思路,再次自觉思维的狭隘!!

#include  < iostream >
using   namespace  std;

#define  MAXN 20010

int  a[MAXN],b[MAXN],array[ 4 ][MAXN], * sa, * nsa, * rank, * nrank,height[MAXN],n;

void  make_sa(){
    
int  i,k;

    sa
= array[ 0 ];
    nsa
= array[ 1 ];
    rank
= array[ 2 ];
    nrank
= array[ 3 ];

    memset(b,
0 , sizeof (b));
    
for (i = 0 ;i < n;i ++ )
        b[a[i]]
++ ;
    
for (i = 1 ;i <= 256 ;i ++ )
        b[i]
+= b[i - 1 ];
    
for (i = n - 1 ;i >= 0 ;i -- )
        sa[
-- b[a[i]]] = i;

    
for (rank[sa[ 0 ]] = 0 ,i = 1 ;i < n;i ++ ){
        rank[sa[i]]
= rank[sa[i - 1 ]];
        
if (a[sa[i]] != a[sa[i - 1 ]])
            rank[sa[i]]
++ ;
    }

    
for (k = 1 ;k < &&  rank[sa[n - 1 ]] < n - 1 ;k *= 2 ){
        
for (i = 0 ;i < n;i ++ )
            b[rank[sa[i]]]
= i;
        
for (i = n - 1 ;i >= 0 ;i -- )
            
if (sa[i] - k >= 0 )
                nsa[b[rank[sa[i]
- k]] -- ] = sa[i] - k;
        
for (i = n - k;i < n;i ++ )
            nsa[b[rank[i]]
-- ] = i;
        
for (nrank[nsa[ 0 ]] = 0 ,i = 1 ;i < n;i ++ ){
            nrank[nsa[i]]
= nrank[nsa[i - 1 ]];
            
if (rank[nsa[i]] != rank[nsa[i - 1 ]]  ||  rank[nsa[i] + k] != rank[nsa[i - 1 ] + k])
                nrank[nsa[i]]
++ ;
        }
        
int   * t = sa;sa = nsa;nsa = t;
        t
= rank;rank = nrank;nrank = t;
    }
}

void  cal_height(){
    
int  i,j,k;
    
for (k = 0 ,i = 0 ;i < n;i ++ ){
        
if (rank[i] == 0 )
            height[rank[i]]
= 0 ;
        
else {
            
for (j = sa[rank[i] - 1 ];a[i + k] == a[j + k];k ++ );
            height[rank[i]]
= k;
            
if (k > 0 )
                k
-- ;
        }
    }
}

bool  OK( int  len){
    
int  i,mn,mx;
    mn
= n;
    mx
= 0 ;
    
for (i = 1 ;i < n;i ++ ){
        
if (height[i] < len){
            mn
= n;
            mx
= 0 ;
        }
        
else {
            
if (sa[i] > mx)
                mx
= sa[i];
            
if (sa[i] < mn)
                mn
= sa[i];
            
if (sa[i - 1 ] > mx)
                mx
= sa[i - 1 ];
            
if (sa[i - 1 ] < mn)
                mn
= sa[i - 1 ];
            
if (mx - mn >= len)
                
return   true ;
        }
    }
    
return   false ;
}

int  main(){
    
int  i,ans,l,r,len;
    
while (scanf( " %d " , & n)  &&  n){
        
for (i = 0 ;i < n;i ++ )
            scanf(
" %d " , & a[i]);
        
for (i = 1 ;i < n;i ++ )
            a[i
- 1 ] = a[i] - a[i - 1 ] + 88 ;
        n
-- ;
        a[n
++ ] = 0 ;

        make_sa();
        cal_height();

        
if ( ! OK( 4 )){
            printf(
" 0\n " );
            
continue ;
        }

        ans
= 0 ;
        l
= 0 ;r = n - 1 ;
        
while (l <= r){
            len
= (l + r) / 2 ;
            
if (OK(len)){
                ans
= len;
                l
= len + 1 ;
            }
            
else
                r
= len - 1 ;
        }
        printf(
" %d\n " ,ans + 1 );

    }
    
return   0 ;
}

你可能感兴趣的:(theme)