zhber
有好多做过的题没写下来,如果我还能记得就补吧

Description

农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。

Input

* Line 1: 两个整数 N,K。

* Lines 2..N+1: 每行一个整数表示当天的质量值。

Output

* Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度

Sample Input

8 2
1
2
3
2
3
2
3
1

Sample Output

4
 
也是SA
height[i]表示字典序排第i的串和字典序排i-1的串的最长公共前缀
然后有一个结论是height[i]>=height[i-1]-1
而且按照后缀的下标排序的话可以让复杂度降到O(n)
具体见2009罗穗骞论文《后缀数组——处理字符串的有力工具》
这题求最长可重复前缀,注意到一旦height[i]<k,那么不可能有一个满足条件的子串同时包含i和i-1
二分答案x,然后统计height[i]>=x的最长连续的一段,如果超过m就可行
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 40010
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int srt[N],a[N],hash[N],h[N],ht[N];
int sa[2][N],rnk[2][N],v[N];
int n,m,k,tt,p,q,ans;
inline void calc_sa(int sa[N],int rnk[N],int SA[N],int RNK[N])
{
	for (int i=1;i<=n;i++)v[rnk[sa[i]]]=i;
	for (int i=n;i>=1;i--)if (sa[i]>k)SA[v[rnk[sa[i]-k]]--]=sa[i]-k;
	for (int i=n-k+1;i<=n;i++)SA[v[rnk[i]]]=i;
	for (int i=1;i<=n;i++)
	RNK[SA[i]]=RNK[SA[i-1]]+(rnk[SA[i]]!=rnk[SA[i-1]]||rnk[SA[i]+k]!=rnk[SA[i-1]+k]);
}
inline void get_sa()
{
	p=0;q=1;a[0]=-1;
	memset(v,0,sizeof(v));
	for (int i=1;i<=n;i++)v[a[i]]++;
	for (int i=1;i<=n;i++)v[i]+=v[i-1];
	for (int i=1;i<=n;i++)sa[p][v[a[i]]--]=i;
	for (int i=1;i<=n;i++)
		rnk[p][sa[p][i]]=rnk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
	for (k=1;k<n;k<<=1,swap(p,q))
		calc_sa(sa[p],rnk[p],sa[q],rnk[q]);
}
inline void get_h()
{
	k=0;
	for(int i=1;i<=n;i++)
	{
		if (rnk[p][i]==1)h[i]=0;
		else
		{
			int j=sa[p][rnk[p][i]-1];
			while (a[i+k]==a[j+k])k++;
			h[i]=k;if (k)k--;
		}
	}
	for (int i=1;i<=n;i++)
		ht[rnk[p][i]]=h[i];
}
inline bool jud(int x)
{
	int temp=0;
	for (int i=1;i<=n;i++)
	{
		if (ht[i]>=x){temp++;if (temp==m-1)return 1;}
		else temp=0;
	}
	return 0;
}
int main()
{
	n=read();m=read();
	for (int i=1;i<=n;i++)srt[i]=a[i]=read();
	sort(srt+1,srt+n+1);srt[0]=-1;
	hash[++tt]=srt[1];
	for (int i=2;i<=n;i++)if (srt[i]!=srt[i-1])hash[++tt]=srt[i];
	for (int i=1;i<=n;i++)a[i]=lower_bound(hash+1,hash+tt+1,a[i])-hash;
	get_sa();
	get_h();
	int l=1,r=n;
	while (l<=r)
	{
		int mid=(l+r)>>1;
		if (jud(mid)){ans=mid;l=mid+1;}
		else r=mid-1;
	}
	printf("%d\n",ans);
	return 0;
}

  

posted on 2015-01-14 09:05  zhber  阅读(272)  评论(0编辑  收藏  举报