pku1743

这个地址上的题解已经好详细了

http://wenku.baidu.com/view/87f5b7f80242a8956bece4df.html

不过本人觉得,加上这部分题解的话,会更好理解

 若在假设重复子串的长度最多为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,*rank1,*nrank,height[MAXN],n;

void make_sa(){
    int i,k;

    sa=array[0];
    nsa=array[1];
    rank1=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(rank1[sa[0]]=0,i=1;i<n;i++){
        rank1[sa[i]]=rank1[sa[i-1]];
        if(a[sa[i]]!=a[sa[i-1]])
            rank1[sa[i]]++;
    }

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

void cal_height(){
    int i,j,k;
    for(k=0,i=0;i<n;i++){
        if(rank1[i]==0)
            height[rank1[i]]=0;
        else{
            for(j=sa[rank1[i]-1];a[i+k]==a[j+k];k++);
            height[rank1[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();
        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;
        }
		if(ans>=4)
        printf("%d\n",ans+1);
		else printf("0\n");

    }
    return 0;
}
#include <stdio.h>   
#include <stdlib.h>   
#include <string.h>   
  
int const N= 20100;   
int wa[N], wb[N], ws[N], wv[N];   
int rank[N], sa[N], height[N], r[N], n, k;   
  
int cmp( int* r, int a, int b, int L ){   
    return r[a]== r[b] && r[a+ L]== r[b+ L];   
}   
  
void da( int* r, int* sa, int n, int m ){   
    int i, j, p, *x= wa, *y= wb, *t;   
    for( i= 0; i< m; ++i ) ws[i]= 0;   
    for( i= 0; i< n; ++i ) ws[ x[i]= r[i] ]++;   
    for( i= 1; i< m; ++i ) ws[i]+= ws[i-1];   
    for( i= n- 1; i>= 0; i-- ) sa[ --ws[ x[i] ] ]= i;   
  
    for( j= 1, p= 1; p< n; j*= 2, m= p ){   
        for( p= 0, i= n- j; i< n; ++i ) y[p++]= i;   
        for( i= 0; i< n; ++i )   
            if( sa[i]>= j ) y[p++]= sa[i]- j;   
  
        for( i= 0; i< n; ++i ) wv[i]= x[y[i]];   
        for( i= 0; i< m; ++i ) ws[i]= 0;   
        for( i= 0; i< n; ++i ) ws[ wv[i] ]++;   
        for( i= 1; i< m; ++i ) ws[i]+= ws[i-1];   
        for( i= n- 1; i>= 0; i-- ) sa[ --ws[ wv[i] ] ]= y[i];   
  
        t= x, x= y, y= t, p= 1; x[ sa[0] ]= 0;   
        for( i= 1; i< n; ++i )   
            x[ sa[i] ]= cmp( y, sa[i-1], sa[i], j )? p- 1: p++;   
    }   
}   
  
void callheight( int* r, int*sa, int n ){   
    int i, j, k= 0;   
    for( i= 1; i<= n; ++i ) rank[ sa[i] ]= i;   
  
    for( i= 0; i< n; height[ rank[i++] ]= k )   
        for( k?k--:0, j= sa[ rank[i]- 1]; r[i+k]== r[j+k]; k++ );   
}  
bool OK(int len)
{
	int mx=0,mi=n;
	for(int i=1;i<n;i++)
	{
		if(height[i]<len)
		{
			mx=0;mi=n;
		}
		else 
		{
			if(sa[i]>mx)
				mx=sa[i];
			if(sa[i-1]>mx)
				mx=sa[i-1];
			if(sa[i]<mi)
				mi=sa[i];
			if(sa[i-1]<mi)
				mi=sa[i-1];
			if(mx-mi>=len)
				return true;
		}
	}
	return false;
}
int main(){  

    int i,ans,l,len,right;  

    while(scanf("%d",&n) && n){  

        for(i=0;i<n;i++)  

            scanf("%d",&r[i]);  

        for(i=1;i<n;i++)  
            r[i-1]=r[i]-r[i-1]+88;  
        n--;    r[n++]=0; 
		da(r,sa,n+1,180);//最后一个参数表示r[]数组的最大值,数组ws[]的大小随最后一个参数而变
		callheight(r,sa,n);
      
        ans=0;  

        l=0;right=n-1;  

        while(l<=right){  

            len=(l+right)/2;  

            if(OK(len)){  

                ans=len;  

                l=len+1;  

            }  

            else 

                right=len-1;  

        }  

        if(ans>=4)  

        printf("%d\n",ans+1);  

        else printf("0\n");  

   

    }  

    return 0;  

} 
posted @ 2011-05-17 22:57  枕边梦  阅读(416)  评论(0编辑  收藏  举报