【BZOJ2288】生日礼物 [贪心]
生日礼物
Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, ..., AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物。
自然地,ftiasch想要知道选择元素之和的最大值。你能帮助她吗?
Input
第1行,两个整数 N 和 M , 序列的长度和可以选择的部分。
第2行, N 个整数 A1, A2, ..., AN , 序列。
Output
一个整数,最大的和。
Sample Input
5 2
2 -3 2 -1 2
2 -3 2 -1 2
Sample Output
5
HINT
1 ≤ N ≤ 105, 0 ≤ M ≤ 105, 0 ≤ |Ai| ≤ 104
Solution
首先,我们可以把权值正负相同的连续的一段合并起来。Ans+=(所有正数),块数++。
然后把每一段的绝对值加入到小根堆里面。每次贪心取出最小的来,块数减去 1 直到满足题目要求为止。
为什么这样可以对呢?我们来讨论一下:
1. 如果删去的段是正数, 那么相当于不取这个。
2. 如果删去的段是负数,那么相当于取了这个段合并它左右的两个段。
但是!这样会有一个问题!就是无法考虑连续取5个段及以上的情况,并且无法保证:取了一个数不取相连的两个数(会导致块数不减)。
所以判断一下,每次取段的时候,删去左右两个小段,加上一个大段(他们三个合并的值)即可。
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream>
2 #include<string>
3 #include<algorithm>
4 #include<cstdio>
5 #include<cstring>
6 #include<cstdlib>
7 #include<cmath>
8 #include<queue>
9 using namespace std;
10 typedef long long s64;
11
12 const int ONE = 200005;
13 const int INF = 1000000007;
14
15 int n, m;
16 int a[ONE], A[ONE];
17 int pre[ONE], suc[ONE];
18 int Ans, block;
19
20 struct power
21 {
22 int id, val;
23 bool operator <(power a) const
24 {
25 return a.val < val;
26 }
27 };
28 priority_queue <power> q;
29
30 int get()
31 {
32 int res=1,Q=1;char c;
33 while( (c=getchar())<48 || c>57 )
34 if(c=='-')Q=-1;
35 res=c-48;
36 while( (c=getchar())>=48 && c<=57 )
37 res=res*10+c-48;
38 return res*Q;
39 }
40
41
42 int main()
43 {
44 n = get(); m = get();
45 for(int i = 1; i <= n; i++) a[i] = get();
46 int from = 1; while(a[from] <= 0) from++;
47 int to = n; while(a[to] <= 0) to--;
48
49 n = 0;
50 for(;from <= to;)
51 {
52 if( (a[from-1] <= 0 && a[from] <= 0) || (a[from-1] > 0 && a[from] > 0))
53 A[n] += a[from];
54 else A[++n] = a[from];
55 from++;
56 }
57
58 for(int i = 1; i <= n; i++)
59 {
60 pre[i] = i - 1;
61 suc[i] = i + 1;
62 if(A[i] > 0) Ans += A[i], block++;
63 A[i] = abs(A[i]);
64 q.push( (power){i, A[i]} );
65 }
66
67 if(block <= m) {printf("%d", Ans); return 0;}
68
69 pre[1] = suc[n] = 0;
70
71 for(;;)
72 {
73 for(;;)
74 {
75 power u = q.top();
76 if(u.val != A[u.id]) q.pop();
77 else break;
78 }
79
80 power u = q.top(); q.pop();
81 Ans -= u.val;
82
83 if(pre[u.id] == 0) A[suc[u.id]] = INF, pre[suc[u.id]] = 0;
84 else
85 if(suc[u.id] == 0) A[pre[u.id]] = INF, suc[pre[u.id]] = 0;
86 else
87 {
88 A[u.id] = A[pre[u.id]] + A[suc[u.id]] - A[u.id];
89 A[pre[u.id]] = A[suc[u.id]] = INF;
90 pre[u.id] = pre[pre[u.id]];
91 suc[u.id] = suc[suc[u.id]];
92 pre[suc[u.id]] = suc[pre[u.id]] = u.id;
93 q.push( (power){u.id, A[u.id]} );
94 }
95
96 block--; if(block <= m) break;
97 }
98
99 printf("%d", Ans);
100 }