BZOJ2288: 【POJ Challenge】生日礼物
2288: 【POJ Challenge】生日礼物
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 771 Solved: 238
[Submit][Status][Discuss]
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
HINT
Source
【题解】
把相连的负数和正数连起来,把0去掉。
这个数组是正负正负.....这样的。不难证明一定是选择连起来后的数组中的若干段数。
先把所有正数加合sum,记录正数的个数now。如果k < m,则sum即为答案。如果k > m,
就要考虑两种决策:
1、选择一个负数,让两个整数连成一段,now -= 1
2、去掉一个正数,now -= 1
可以发现,其实这两个决策都相当于sum减去数列中某一个数的绝对值。
选了一个数后,这个数周围两个数不可再选。且要么选最小的数,要么选最小的数
旁边的两个数。
瞬间变成了BZOJ1150那个题目。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <queue> 6 #include <vector> 7 8 inline void read(int &x) 9 { 10 char ch = getchar(), c = ch;x = 0; 11 while(ch < '0' || ch > '9')c = ch, ch = getchar(); 12 while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); 13 if(c == '-')x = -x; 14 } 15 16 const int INF = 0x3f3f3f3f; 17 const int MAXN = 100000 + 10; 18 const int MAXM = 100000 + 10; 19 20 int n,m,tmp,num[MAXN],cnt1,now,sum,cnt; 21 int flag; 22 23 struct Node 24 { 25 int pre,nxt,value; 26 Node(int _pre, int _nxt, int _value) 27 { 28 pre = _pre;nxt = _nxt;value = _value; 29 } 30 Node(){} 31 }node[MAXN * 4]; 32 33 int b[MAXN * 4]; 34 35 struct cmp 36 { 37 bool operator()(int a, int b) 38 { 39 return node[a].value > node[b].value; 40 } 41 }; 42 43 std::priority_queue<int, std::vector<int>, cmp> q; 44 45 int main() 46 { 47 read(n), read(m); 48 while(tmp == 0) read(tmp); 49 if(tmp > 0)flag = 1; 50 else flag = 0; 51 num[++cnt1] += abs(tmp); 52 for(register int i = 1;i <= n;++ i) 53 { 54 read(tmp); 55 if(tmp == 0)continue; 56 else if(tmp > 0 && !flag)++ cnt1, flag = 1; 57 else if(tmp < 0 && flag)++ cnt1, flag = 0; 58 num[cnt1] += tmp; 59 } 60 if(num[1] < 0)num[1] = INF; 61 if(num[cnt1] < 0)num[cnt1] = INF; 62 for(register int i = 1;i <= cnt1;++ i) 63 { 64 node[++cnt] = Node(cnt - 1, cnt + 1, abs(num[i])); 65 if(num[i] > 0 && num[i] != INF)sum += num[i], ++now; 66 q.push(cnt); 67 } 68 node[0] = Node(0, 1, INF); 69 ++ cnt; 70 node[cnt] = Node(cnt - 1, 0, INF); 71 while(q.size() && now > m) 72 { 73 int tmp = q.top(); q.pop(); 74 if(b[tmp])continue; 75 int pre = node[tmp].pre, nxt = node[tmp].nxt; 76 b[tmp] = b[pre] = b[nxt] = 1; 77 sum -= node[tmp].value;-- now; 78 ++ cnt; 79 node[node[pre].pre].nxt = cnt; 80 node[node[nxt].nxt].pre = cnt; 81 node[cnt] = Node(node[pre].pre, node[nxt].nxt, node[pre].value + node[nxt].value - node[tmp].value); 82 } 83 printf("%d", sum); 84 return 0; 85 }