HDOJ 题目3530 Subsequence(队列)

11 篇文章 0 订阅

Subsequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4540    Accepted Submission(s): 1489


Problem Description
There is a sequence of integers. Your task is to find the longest subsequence that satisfies the following condition: the difference between the maximum element and the minimum element of the subsequence is no smaller than m and no larger than k.
 

Input
There are multiple test cases.
For each test case, the first line has three integers, n, m and k. n is the length of the sequence and is in the range [1, 100000]. m and k are in the range [0, 1000000]. The second line has n integers, which are all in the range [0, 1000000].
Proceed to the end of file.
 

Output
For each test case, print the length of the subsequence on a single line.
 

Sample Input
  
  
5 0 0 1 1 1 1 1 5 0 3 1 2 3 4 5
 

Sample Output
  
  
5 4
 

Source
 

Recommend
zhengfeng   |   We have carefully selected several similar problems for you:   3535  3529  3528  3527  3415 
只能说不懂,,先珍藏一下吧
思路: http://www.cnblogs.com/yymore/archive/2011/06/22/2087553.html

首先我们要明确几件事情

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。

 
ac代码
#include<string.h>
#include<stdio.h>
int f[1000100],d1[1000100],d2[1000100];
int main()
{
	int n,m,k;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		int i;
		int l1,l2,r1,r2,ans,st;
		l1=l2=ans=st=0;
		r1=r2=-1;
		memset(f,0,sizeof(f));
		memset(d1,0,sizeof(d1));
		memset(d2,0,sizeof(d2));
		for(i=1;i<=n;i++)
		{
			scanf("%d",&f[i]);
			while(l1<=r1&&f[d1[r1]]>=f[i]) r1--;
			d1[++r1]=i;
			while(l2<=r2&&f[d2[r2]]<=f[i]) r2--;
			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);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值