BZOJ2288: POJ Challenge生日礼物

Posted 嘒彼小星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2288: POJ Challenge生日礼物相关的知识,希望对你有一定的参考价值。

2288: 【POJ Challenge】生日礼物

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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那个题目。

 

技术分享
 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 }
BZOJ2288

 

以上是关于BZOJ2288: POJ Challenge生日礼物的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2288 POJ Challenge生日礼物

[bzoj2288][POJ Challenge]生日礼物

BZOJ 2288 POJ Challenge生日礼物(贪心+优先队列)

bzoj 2288: POJ Challenge生日礼物链表+堆

BZOJ3502/2288PA2012 Tanie linie/POJ Challenge生日礼物 堆+链表(模拟费用流)

Bzoj 2288 生日礼物题解