poj3261(后缀数组)

题意:给出一串长度为n的字符,再给出一个k值,要你求重复次数大于等于k次的最长子串长度........

思路:其实也非常简单,直接求出height值,然后将它分组,二分答案......结果就出来了.......

#include<iostream>

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

#define maxx 110000

int wa[maxx],wb[maxx],wsf[maxx],wv[maxx];

int sa[maxx],rank[maxx],s[maxx],height[maxx];

struct node

{

	int num,x;

}str[maxx];

int cmp1(const node a,const node b)

{

	if(a.x<b.x)

	return 1;

	else

	return 0;

}

int cmp(int *r,int a,int b,int k)

{

	return r[a]==r[b]&&r[a+k]==r[b+k];

} 

void getsa(int *r,int *sa,int n,int m)

{

	int i,j,p,*x=wa,*y=wb,*t;

	for(i=0;i<m;i++)  wsf[i]=0;

	for(i=0;i<n;i++)  wsf[x[i]=r[i]]++;

	for(i=1;i<m;i++)  wsf[i]+=wsf[i-1];

	for(i=n-1;i>=0;i--)  sa[--wsf[x[i]]]=i;

	j=1;

	p=1;

	for(;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++)  wsf[i]=0;

		for(i=0;i<n;i++)  wsf[wv[i]]++;

		for(i=1;i<m;i++)  wsf[i]+=wsf[i-1];

		for(i=n-1;i>=0;i--)  sa[--wsf[wv[i]]]=y[i];

		t=x;

		x=y;

		y=t;

		x[sa[0]]=0;

		for(p=1,i=1;i<n;i++)   x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;

	}

}

void getheight(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;i++)

	{

		if(k)

		k--;

		else

		k=0;

		j=sa[rank[i]-1];

		while(r[i+k]==r[j+k])

		k++;

		height[rank[i]]=k;

	}

}

int deal(int n,int mid,int k)

{

	int flag=1;                     //要注意,初始值是1.....应该一个height值,是两个字符的lcp,i与i-1的....所以初始值应该从1开始.... 

	for(int i=2;i<=n;i++)

	{

		if(height[i]>=mid)

		{

			flag++;

			if(flag>=k)

			return 1;

		}

		else  flag=1;

	}

	return 0;

}

int main()

{

	int n,k;

	while(scanf("%d%d",&n,&k)>0)

	{

		int zd=0;

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

		{

			scanf("%d",&str[i].x);

			str[i].num=i;

		}

		sort(str,str+n,cmp1);

		int j=1;

		s[str[0].num]=j;

		for(int i=1;i<n;i++)

		{

			if(str[i].x==str[i-1].x)

			s[str[i].num]=j;

			else

			{

				j++;

				s[str[i].num]=j;

			}

		}

		s[n]=0;

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

		//printf("%d ",s[i]);

		getsa(s,sa,n+1,j+10);

		getheight(s,sa,n);

		int left=0,right=n,count=0,mid;

		while(left<=right)

		{

			mid=(left+right)/2;

			if(deal(n,mid,k))

			{

				if(count<mid)

				count=mid;

				//printf("%d\n",mid);

				left=mid+1;

			}

			else  right=mid-1;

		}

		printf("%d\n",count);

	}

	return 0;

}

 

你可能感兴趣的:(后缀数组)