bzoj2288 【POJ Challenge】生日礼物

【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

<br >
<br >
<br >
<br >
<br >
<br >

抱着线段树的心态来做这道题。。。结果怎么想怎么贪心。。。
先说一下步骤:
先同号的合并,然后把前后的负数直接去掉(最简单的贪心策略)
然后就是一通操作了。。。。先把所有正项加起来,然后特判一下之后,把每个数的绝对值存进堆里。
小根堆贪心,如果这个数原本是个正数,那么减去他代表不选他,如果是个负数,那么减去他代表合并他的左右两个。
为什么是对的呢?我们可以大致脑补一下:
首先,如果全是正数,显然去掉最小的。
先说为什么无脑选最小的正项删去不对:
假设已经初步处理过的数列是:6 -4 3 -2 7 选两段
如果我们直接去掉3的话就是13,但是如果我们合并后三项的话可以取到14.
那么这种bug什么时候会出现呢?我真的觉得我的破脑袋里不知道装了些啥,反正我是这样瞎想的:
假设我有一个数列A;
如果我把这个数列中的一个负项变成0,这个新数列B的答案不可能变的更差,对吧。
紧接着,我们把B中的一个正项变的更大,这样也不会让答案变的更差。
其实我们把一个负数进行合并就是这么一个过程。去掉一个负项和两个正项,然后加一个更好的正项,(在m允许的范围内是正确的)
这样,我们稍微思考一下就会发现,在m允许的情况下,上述方法是正确的。
(大致感受一下就好了。。。)

<br >
<br >


#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;
}

posted @ 2018-05-17 12:14  沛霖  阅读(240)  评论(0编辑  收藏  举报