bzoj2288 【POJ Challenge】生日禮物
阿新 • • 發佈:2018-05-17
小根堆 names ret 神奇 HA 感受 printf mes pac
如果我們直接去掉3的話就是13,但是如果我們合並後三項的話可以取到14.
那麽這種bug什麽時候會出現呢?我真的覺得我的破腦袋裏不知道裝了些啥,反正我是這樣瞎想的:
假設我有一個數列A;
如果我把這個數列中的一個負項變成0,這個新數列B的答案不可能變的更差,對吧。
緊接著,我們把B中的一個正項變的更大,這樣也不會讓答案變的更差。
其實我們把一個負數進行合並就是這麽一個過程。去掉一個負項和兩個正項,然後加一個更好的正項,(在m允許的範圍內是正確的)
這樣,我們稍微思考一下就會發現,在m允許的情況下,上述方法是正確的。
(大致感受一下就好了。。。)
【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 選兩段
那麽這種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】生日禮物