BZOJ1717: [Usaco2006 Dec]Milk Patterns 产奶的模式 后缀数组

1717: [Usaco2006 Dec]Milk Patterns 产奶的模式

Time Limit: 5 Sec   Memory Limit: 64 MB
Submit: 1064   Solved: 580
题解:
后缀数组求出来Height数组,然后求出相邻的K个串的LCP即可,不需要让串的长度大于K,因为等于K一定比大于K更优,单调队列维护连续k-1个height里的最小值(因为k-1个height相当于k的串的LCP)。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
const int N=200010;
using namespace std;
int n,k;
int m,p,wa[N],wb[N],SA[N],RK[N],HE[N],c[N],cnt,q[N],ans;
char s[N];
void GetSA()
{
	int *x=wa,*y=wb;
	m=255,p=0;
	for (int i=1;i<=n;i++) c[x[i]=s[i]]++;
	for (int i=1;i<=m;i++) c[i]+=c[i-1];
	for (int i=n;i>=1;i--) SA[c[x[i]]--]=i;
	for (int k=1;p<n;k<<=1)
	{
		p=0;
		for(int i=n-k+1;i<=n;i++) y[++p]=i;
		for(int i=1;i<=n;i++)
		if(SA[i]>k) y[++p]=SA[i]-k;
		memset(c,0,sizeof(c));
		for(int i=1;i<=n;i++) c[x[y[i]]]++;
		for(int i=1;i<=m;i++) c[i]+=c[i-1];
		for(int i=n;i>=1;i--) SA[c[x[y[i]]]--]=y[i];
		swap(x,y);
		p=1;
		x[SA[1]]=p;
		for(int i=2;i<=n;i++)
		{
			if(y[SA[i]]!=y[SA[i-1]]||y[SA[i]+k]!=y[SA[i-1]+k]) p++;
			x[SA[i]]=p;
		}
		m=p;
	}
}
void GetRK()
{
	for(int i=1;i<=n;i++) RK[SA[i]]=i;
}
void GetHE()
{
	int j=0;
	for(int i=1;i<=n;i++)
	{
		if(RK[i]==1) continue;
		while(s[i+j]==s[SA[RK[i]-1]+j]) j++;
		HE[RK[i]]=j;
		if(j) j--;
	}
}  
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
	GetSA(),GetRK(),GetHE();
	int h=1,t=0;
	k--;
	for(int i=1;i<=n;i++)
	{
		while(h<=t&&q[h]<=i-k) h++;
		while(h<=t&&HE[i]<HE[q[t]]) t--;
		q[++t]=i;
		if(i>=k) ans=max(ans,HE[q[h]]);
	}
	printf("%d",ans);
}


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

HINT

Source

[Submit][Status][Discuss]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值