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;
}
posted @ 2008-11-24 00:43  Beetlebum  阅读(505)  评论(8编辑  收藏  举报