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;
}

 

posted @ 2013-07-17 15:21  紫忆  阅读(237)  评论(0编辑  收藏  举报