這個題目屬於常見題型,給定一組環狀數列,求出其中長度不超過k的數字之和的最大值。。
用到了字首和的技巧,比如要求i,j間所有數字之和,可以提前在輸入的時候計算出從0~i的數字之和及從0~j的數字之和,那麼sum[i~j]=sum[j]-sum[i];
現在的問題是求出最大的sum[i~j].那麼我們可以固定sum[j]的值,當sum[i]最小時,整個式子值最大。。顯然會用到單調遞增佇列,不斷維護進隊出隊操作即可,
保持單調遞增佇列的單調性不被破壞,則隊頭元素始終是最小的值;
至於sum[j]不斷列舉就行了,至此問題得到完美解決。
下面是我的**,調了半天才發現乙個極其sb的錯誤,維護進隊操作時,應該用sum[q[tail]]和sum[cur]比較進行刪除隊尾元素的操作,我不知道為何手賤的寫成了sum[q[head]]......t_t,地球人已經阻止不了我犯二的腳步了~~qaq
/******************************
* author :crazy_石頭
* data structure: 單調佇列
* created time:2013/112/31 23:27
* pro:hdoj 3415
* judge status:accepted
* memory:2098k
* time:171ms
* ps:可以優化輸入輸出加速,orz
* 這題也很基礎,不過多了起始點和結束點的維護罷了;
*******************************/
#include
#include
#include
#include
usingnamespacestd;
#define rep(i,h,m) for(int i=(h);i<=(m);i++)
#define inf
0x3fffffff
const
int maxn=100000+5;
int sum[maxn<<1],q[maxn<<1],a[maxn<<1];//q儲存下標,元素的值可以通過訪問下標間接訪問到;
int res,test;
int head,tail,n,k;
int start,end;
inlinevoid enqueue(int cur)//維護單調遞增隊列入隊過程;
inlinevoid dequeue(int cur)//不斷維護該操作即可;
}int main()
rep(i,n+1,n+k)
sum[i]=sum[i-1]+a[i-n];//處理迴圈數列的方法:在其後面複製一串數字;
enqueue(0);
rep(i,1,n+k)
printf("%d %d %d\n",res,start>n?start-n:start,end>n?end-n:end);
}return0;}
* this source code was highlighted byycdoit
. ( style: fog )
HDU3415單調佇列
這題是單調佇列的典型運用。至於單調佇列,就是乙個雙端佇列,在隊首 f 出隊,在隊尾 b 出隊入隊,我們要維護整個佇列的元素是單調的,比如,我們要動態查詢從左向右的區間的最小值,那麼我們就要在佇列中維護乙個單調遞增的序列,從左向右列舉,佇列的元素還有乙個id值,代表這個元素在原序列中的位置,然後左邊的...
HDU3415單調佇列
這題是單調佇列的典型運用。至於單調佇列,就是乙個雙端佇列,在隊首 f 出隊,在隊尾 b 出隊入隊,我們要維護整個佇列的元素是單調的,比如,我們要動態查詢從左向右的區間的最小值,那麼我們就要在佇列中維護乙個單調遞增的序列,從左向右列舉,佇列的元素還有乙個id值,代表這個元素在原序列中的位置,然後左邊的...
HDU 3415 單調佇列
求長度不大於 k 的最大子段和 求字首和,列舉答案的右端點,對於每個右端點,求以該點為右端點,長度為 k 的區間的最小值 用單調佇列維護值單調遞增的下標,對於每個右端點,若隊首元素與當前位置的距離不滿足要求,則出隊,否則記錄答案 includeusing namespace std typedef ...