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

 

转载于:https://www.cnblogs.com/huibixiaoxing/p/7472101.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值