【題目地址】
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; }