YY_More

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

这道题很有意思,需要巧妙地套用单调队列

首先我们要明确几件事情

1.假设我们现在知道序列(i,j)是符合标准的,那么如果第j+1个元素不比(i,j)最大值大也不比最小值小,那么(i,j+1)也是合法的

2.如果(i,j)不合法的原因是差值比要求小,那在(i,j)范围内的改动是无效的,需要加入j+1元素充当最大值或者最小值才可能获得合法的序列

3.假设序列(i,j)的差值比要求大,那么我们必须将其中的最大值或者最小值从序列中删除出去,才可能获得一个合法的序列,只往里加入元素是不可能令序列合法的

基于以上几点考虑,我们可以利用单调队列完成我们的算法。

设定一个变量ST作为当前合法序列的开端(对于一个序列(i,j),其对应的ST为i-1),初始值是0

设f[i]是以第i个元素结尾的最长合法序列长度,我们把i加入两个单调队列中维护,一个维护i之前的最小值,一个是最大值。

情况1.如果最大值和最小值的差值在范围之内,那么(ST,i)是合法序列,f[i]=i-ST。

情况2.如果差值比要求小,则没有以i结尾的合法序列,f[i]=0。

情况3.如果差值比要求大,那么需要删除最大值或者最小值,怎么删除?当然是删除最大值和最小值中靠前的那个,同时ST相应更新,直到情况1或者情况2。

//By YY_More
#include<cstdio>
int n,m,k,h,D1[100010],D2[100010],f[100010];
int main(){
	int ans,ST,L1,R1,L2,R2;;
	while (~scanf("%d%d%d",&n,&m,&k)){
		L1=L2=ans=ST=0;R1=R2=-1;
		for (int i=1;i<=n;i++){
			scanf("%d",&f[i]);
			while (L1<=R1&&f[D1[R1]]>=f[i]) R1--;//min
			D1[++R1]=i;
			while (L2<=R2&&f[D2[R2]]<=f[i]) R2--;//max
			D2[++R2]=i;
			while (f[D2[L2]]-f[D1[L1]]>k)
				if (D1[L1]<D2[L2]){
					ST=D1[L1];
					L1++;
				}else{
					ST=D2[L2];
					L2++;
			}	
	    	if (f[D2[L2]]-f[D1[L1]]>=m&&i-ST>ans) ans=i-ST;
		}
		printf("%d\n",ans);
	}		
	return 0;
}
posted on 2011-06-22 20:16  YY_More  阅读(340)  评论(0编辑  收藏  举报