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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章