1. 程式人生 > >bzoj2288 【POJ Challenge】生日禮物

bzoj2288 【POJ Challenge】生日禮物

小根堆 names ret 神奇 HA 感受 printf mes pac

【POJ Challenge】生日禮物

Time Limit: 10 Sec Memory Limit: 128 MB

Description

ftiasch 18歲生日的時候,lqp18_31給她看了一個神奇的序列 A1, A2, ..., AN. 她被允許選擇不超過 M 個連續的部分作為自己的生日禮物。
自然地,ftiasch想要知道選擇元素之和的最大值。你能幫助她嗎?
技術分享圖片

Input

第1行,兩個整數 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105), 序列的長度和可以選擇的部分。
第2行, N 個整數 A1, A2, ..., AN (0 ≤ |Ai| ≤ 104), 序列。

Output

一個整數,最大的和。

Sample Input

5 2
2 -3 2 -1 2

Sample Output

5












抱著線段樹的心態來做這道題。。。結果怎麽想怎麽貪心。。。
先說一下步驟:
先同號的合並,然後把前後的負數直接去掉(最簡單的貪心策略)
然後就是一通操作了。。。。先把所有正項加起來,然後特判一下之後,把每個數的絕對值存進堆裏。
小根堆貪心,如果這個數原本是個正數,那麽減去他代表不選他,如果是個負數,那麽減去他代表合並他的左右兩個。
為什麽是對的呢?我們可以大致腦補一下:
首先,如果全是正數,顯然去掉最小的。
先說為什麽無腦選最小的正項刪去不對:
假設已經初步處理過的數列是:6 -4 3 -2 7 選兩段

如果我們直接去掉3的話就是13,但是如果我們合並後三項的話可以取到14.
那麽這種bug什麽時候會出現呢?我真的覺得我的破腦袋裏不知道裝了些啥,反正我是這樣瞎想的:
假設我有一個數列A;
如果我把這個數列中的一個負項變成0,這個新數列B的答案不可能變的更差,對吧。
緊接著,我們把B中的一個正項變的更大,這樣也不會讓答案變的更差。
其實我們把一個負數進行合並就是這麽一個過程。去掉一個負項和兩個正項,然後加一個更好的正項,(在m允許的範圍內是正確的)
這樣,我們稍微思考一下就會發現,在m允許的情況下,上述方法是正確的。
(大致感受一下就好了。。。)





#include<bits/stdc++.h>
#define lpl pair<int, int> using namespace std; const int maxn = 1e5 + 5, INF = 211199921; bool flag[maxn]; int n, m, s, t, ans, ini[maxn], num[maxn], l[maxn], r[maxn]; priority_queue< lpl, vector<lpl>, greater<lpl> > q; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){ x = 10 * x + ch - '0'; ch = getchar();} return x * f; } inline void putit() { t = read(); m = read(); s = 1; for(int i = 1; i <= t; ++i){ ini[i] = read(); } while(ini[t] <= 0) t--; while(ini[s] <= 0) s++; for(; s <= t; s++) if((ini[s] > 0 && ini[s - 1] > 0) || (ini[s] <= 0 && ini[s - 1] <= 0)) num[n] += ini[s]; else num[++n] = ini[s]; //for(int i = 1; i <= n; ++i) printf("%d ", num[i]); } inline void workk() { for(int i = 1; i <= n; ++i) if(num[i] > 0) {ans += num[i], m--;} else num[i] = -num[i]; if(m >= 0){cout << ans; return;} for(int i = 1; i <= n; ++i){ l[i] = i - 1, r[i] = i + 1, q.push(lpl(num[i], i)); } m = -m; r[n] = 0; int x; while(m--){ while(q.top().first != num[q.top().second]) q.pop(); x = q.top().second; q.pop(); ans -= num[x]; if(!l[x]){ num[r[x]] = INF; l[r[x]] = 0; continue; } if(!r[x]){ num[l[x]] = INF; r[l[x]] = 0; continue; } num[x] = num[l[x]] + num[r[x]] - num[x]; num[l[x]] = num[r[x]] = INF; l[x] = l[l[x]]; r[x] = r[r[x]]; r[l[x]] = l[r[x]] = x; q.push(lpl(num[x], x)); } cout << ans; } int main() { putit(); workk(); return 0; }

bzoj2288 【POJ Challenge】生日禮物