什么是不重叠最长子串呢,就是一个串中至少出现两次,又不重叠的子串中的最长的,比较绕口。

  解决这个问题的关键还是利用height 数组。把排序后的后缀分成若干组,其中每组的后缀之间的height 值都不小于k。然后找出各个组的后缀的sa值的最大最小值max,min,如果存在 max-min >= k,那么就存在长度为k的不重叠子串,因为根据LCP定理,每个组中的height值都不小于k,就是说这个组中这些后缀的最长公共前驱最小是k,然后由于max-min>= k,所以可以判定存在所要求的子串。做题的时候二分答案,把问题变为判定性问题(大牛说的)。那么整个事件复杂度为O(nlogn)。把height数组分组的思想非常常用,可以多看看IOI论文了解了解。

  pku 1743,题本身不难,可是,万恶的英语啊.....

#include<stdio.h>
#include<string.h>
#define MAX 20010
int wx[MAX],wy[MAX],bar[MAX],r[MAX];
int cmp(int *s,int a,int b,int len)
{return s[a] == s[b] && s[a+len] == s[b+len];}
void get_sa(int *note,int *sa,int len)
{
	int *Rank = wx,*result_y = wy,*result = r,*t,i,m = 200;
	for (i = 0; i<= m; i++)  bar[i] = 0;
	for (i = 0; i< len; i++) bar[Rank[i] = note[i]] ++;
	for (i = 0; i< m; i++) bar[i+1] += bar[i];
	for (i = len-1; i>= 0; i--) sa[--bar[Rank[i]]] = i;
	for (int k = 1,p = 1; p < len; k *= 2,m = p){
		for (p = 0,i = len-k; i < len; i++) result_y[p++] = i;
		for (i = 0; i < len; i++) if (sa[i] >= k) result_y[p++] = sa[i] - k;

		for (i = 0; i < len; i++) result[i] = Rank[result_y[i]];
		for (i = 0; i <= m; i++) bar[i] = 0;
		for (i = 0; i< len; i++) bar[result[i]]++;
		for (i = 0; i< m; i++) bar[i+1] += bar[i];
		for (i = len-1; i>= 0; i--) sa[--bar[result[i]]] = result_y[i];
		for (t = result_y,result_y = Rank,Rank = t,p = 1,Rank[sa[0]] = 0,i = 1; i < len; i++)
			Rank[sa[i]] = cmp(result_y,sa[i],sa[i-1],k)?p-1:p++;
	}
}
void get_height(int *note,int *sa,int *height,int len)
{
	int Rank[MAX],i,j,k = 0;
	for (i = 1; i < len; i++) Rank[sa[i]] = i;
	for (i = 0; i< len-1; height[Rank[i++]] = k)
		for (k?k--:0,j = sa[Rank[i] - 1]; note[i+k] == note[j+k]; k++) ;
}
bool check(int *sa,int *height,int n,int mid)
{
	int max = sa[1], min = sa[1];	
	for (int i = 2; i < n; i++) {		
		if (height[i] >= mid) {			
			if(sa[i]<min) min = sa[i];
			if(sa[i]>max) max = sa[i];		
			if(max-min>mid) return true;			
		} else	max=min=sa[i];
	}
	return false;
}
int main()
{
	int sa[20010],height[20010],note[20010];
	int n,i,j,k;
	while (scanf ("%d",&n) && n)
	{
		int t1,t2;
		scanf ("%d",&t1);
	    for (i = 0; i< n-1; i++){  
			scanf ("%d",&t2);
			note[i] = t2 - t1 + 88;
			t1 = t2;
		}
		note[n-1] = 0;
		get_sa(note,sa,n);
		get_height(note,sa,height,n);
		/*
		for (i = 1; i< n; i++)
			printf ("%d %d\n",i,height[i]);
		*/
	    int s = 1,e = n/2,mid = (s+e)/2;
		while (s <= e)
		{
			int mid = (s + e) >> 1;
            if (check (sa,height,n, mid)) s = mid + 1;
            else e = mid - 1;

		}
    	if (e >= 4)
			printf("%d\n", e+1);
        else printf("0\n");


	}
	return 0;
}

posted on 2010-07-18 15:54  looker  阅读(2194)  评论(0编辑  收藏  举报