什么是不重叠最长子串呢,就是一个串中至少出现两次,又不重叠的子串中的最长的,比较绕口。
解决这个问题的关键还是利用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;
}
浙公网安备 33010602011771号