HDU 3530 Subsequence 【单调队列】

【题目地址】

  http://acm.hdu.edu.cn/showproblem.php?pid=3530

【题目大意】

  给定一个数列,长度n(1<=n<=100000), 值m和k, 求最长子序列,满足当中的最大值-最小值差不小于m且不大于k。

【解题思路】

  朴素的O(n^3)的算法很容易想到,但是显然会超时。

  假设当前枚举区间起点i,维护i到j之间的最大值和最小值,可以得到O(n^2)的算法,仍然超时。

  用两个单调队列(一个递减,一个递增)来维护区间最小值和最大值。

  假设now为区间起始点,枚举到i时,两个队列队头保留的是now到i的最大值和最小值。

  当两个队头元素的差大于k时,删除其中一个队列队头,now要变大。

  我们同时记录队列中元素的在数列中的下标,删除两个队头下标小的元素,now更新为该元素的下一个。

  做了删除之后,判断队头元素的差是否条件,如果满足,那么当前能得到一个序列,长度为i-now+1,找出最大的一个即可。

PS:据说上述O(n^2)的算法,优化后也可以AC。

 

【代码】

#include<cstdio> 
#define maxn 100010
struct Dq {
	int val,pos;
}q1[maxn],q2[maxn],temp;
int main()
{
	int n,m,k,i,h1,h2,t1,t2,now,ans;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF){
		h1=h2=now=ans=0;
		t1=t2=-1;
		for(i=0;i%d",&temp.val),temp.pos=i;
			while(h1<=t1&&q1[t1].val<=temp.val)
				t1--;
			q1[++t1]=temp;
			while(h2<=t2&&q2[t2].val>=temp.val)
				t2--;
			q2[++t2]=temp;
			while(q1[h1].val-q2[h2].val>k){
				if(q1[h1].poselse {
					now=q2[h2].pos+1;h2++;
				}
			}
			if(q1[h1].val-q2[h2].val<=k&&q1[h1].val-q2[h2].val>=m)
				ans=ans>i-now+1?ans:i-now+1;
		}
		printf("%d/n",ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章