BZOJ2288 【POJ Challenge】生日礼物 【堆 + 链表】
题目
ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, ..., AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物。
自然地,ftiasch想要知道选择元素之和的最大值。你能帮助她吗?

输入格式
第1行,两个整数 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105), 序列的长度和可以选择的部分。
第2行, N 个整数 A1, A2, ..., AN (0 ≤ |Ai| ≤ 104), 序列。
输出格式
一个整数,最大的和。
输入样例
5 2
2 -3 2 -1 2
输出样例
5
题解
我们把连续的同号元素合并
得到的序列就是正负交错的序列
加入正数数量<=m,全部选掉就是答案
若正数数量>m,就对于某些数意味着
①不选该正数
②多选一个负数使得相邻正数相连,这样相当于可以少放弃一个正数
我们先将正数总和求出来
然后将所有数的绝对值加入小根堆
每次选出一个减去,然后与邻近的合并【就像选m个不相邻的数和最小一样】
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define ls (u << 1)
#define rs (u << 1 | 1)
#define fa (u >> 1)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int pre[maxn],nxt[maxn],val[maxn],n,m,A[maxn],V[maxn],tot,cnt;
struct node{int v,u;}H[2 * maxn];
int hsiz,pos[2 * maxn];
int pd(int u){
int small;
while (true){
small = u;
if (ls <= hsiz && H[ls].v < H[small].v) small = ls;
if (rs <= hsiz && H[rs].v < H[small].v) small = rs;
if (small != u){
pos[H[small].u] = u; pos[H[u].u] = small;
swap(H[small],H[u]);
u = small;
}else break;
}
return u;
}
void pup(int u){
while (u > 1 && H[fa].v > H[u].v){
pos[H[fa].u] = u; pos[H[u].u] = fa;
swap(H[fa],H[u]);
u = fa;
}
}
void ins(int u){
H[++hsiz] = (node){val[u],u}; pos[hsiz] = u;
pup(hsiz);
}
void del(int u){
pos[H[hsiz].u] = u;
swap(H[u],H[hsiz--]);
u = pd(u);
pup(u);
}
int main(){
n = read(); m = read();
REP(i,n){
A[++tot] = read();
if (!A[tot]) tot--;
}
int x = 1;
while (A[x] < 0 && x <= tot) x++;
if (x > tot) {puts("0"); return 0;}
V[n = 1] = A[x];
while (A[tot] < 0 && tot) tot--;
if (!tot) {puts("0"); return 0;}
for (int i = x + 1; i <= tot; i++){
if ((A[i] < 0 && A[i - 1] < 0) || (A[i] > 0 && A[i - 1] > 0))
V[n] += A[i];
else V[++n] = A[i];
}
cnt = n / 2 + 1;
if (cnt <= m){
sort(V + 1,V + 1 + n);
int ans = 0;
for (int i = 0; i < cnt && V[n - i] > 0; i++) ans += V[n - i];
printf("%d\n",ans);
}else {
int ans = 0;
for (int i = 1; i <= n; i++){
if (V[i] > 0) ans += V[i];
val[i] = abs(V[i]);
if (i > 1) pre[i] = i - 1;
if (i < n) nxt[i] = i + 1;
ins(i);
}
int t = cnt - m,x; node u;
while (t--){
u = H[1]; x = u.u;
ans -= u.v;
if (!pre[x]){
del(1); del(pos[nxt[x]]);
pre[nxt[nxt[x]]] = 0;
}else if (!nxt[x]){
del(1); del(pos[pre[x]]);
nxt[pre[pre[x]]] = 0;
}else {
int l = pre[x],r = nxt[x];
del(pos[l]); del(pos[r]);
H[1].v = val[x] = val[l] + val[r] - val[x]; pos[x] = 1;
pd(1);
nxt[pre[x] = pre[l]] = x;
pre[nxt[x] = nxt[r]] = x;
}
}
printf("%d\n",ans);
}
return 0;
}
BZOJ2288 【POJ Challenge】生日礼物 【堆 + 链表】的更多相关文章
- BZOJ3502PA2012Tanie linie&BZOJ2288[POJ Challenge]生日礼物——模拟费用流+链表+堆
题目描述 n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. 输入 输出 样例输入 5 2 7 -3 4 -9 5 样例输出 13 根据 ...
- [bzoj2288][POJ Challenge]生日礼物
用堆维护双向链表来贪心... 数据范围显然不容许O(nm)的傻逼dp>_<..而且dp光是状态就n*m个了..显然没法优化 大概就会想到贪心乱搞了吧...一开始想贪心地通过几段小的负数把正 ...
- BZOJ 2288: 【POJ Challenge】生日礼物 堆&&链表
就是堆+链表,十分像 数据备份 对吧? 把相邻的正数和相邻的负数合并成一整个正数块和负数块,最后只剩一些交替相间的正块与负块了吧? 显然,正块的个数<=m时,全部选走就获得了最大权值,否则我们可 ...
- 【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)
[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sam ...
- BZOJ2288:[POJ Challenge]生日礼物——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2288 ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, . ...
- BZOJ2288:[POJ Challenge]生日礼物
浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?id ...
- [bzoj2288]【POJ Challenge】生日礼物_贪心_堆
[POJ Challenge]生日礼物 题目大意:给定一个长度为$n$的序列,允许选择不超过$m$个连续的部分,求元素之和的最大值. 数据范围:$1\le n, m\le 10^5$. 题解: 显然的 ...
- 2288.【POJ Challenge】生日礼物 链表+堆+贪心
BZOJ2288 [POJ Challenge]生日礼物 题意: 给一个长度为\(n\)的数组,最多可以选\(m\)个连续段,问选取的最大值是多少 题解: 先把连续的符号相同的值合并,头和尾的负数去掉 ...
- bzoj2288【POJ Challenge】生日礼物*
bzoj2288[POJ Challenge]生日礼物 题意: 给一个序列,求不超过m个连续的部分,使元素和最大.序列大小≤100000 题解: 先把连续的正数和负数合并起来,接着如果正数个数小于m则 ...
- 【链表】BZOJ 2288: 【POJ Challenge】生日礼物
2288: [POJ Challenge]生日礼物 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 382 Solved: 111[Submit][S ...
随机推荐
- JBOSS默认连接池配置
jboss5.0mysql连接配置 <?xml version="1.0" encoding="UTF-8"?> <!-- The Hyper ...
- Android学习总结(六)———— 发送自定义广播
一.两种广播类型 2.1 标准广播 是一种完全异步执行的广播,在广播发出去之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言.这种广播的效率会比较高,但同时也 ...
- 电脑公司最新稳定win7系统下载
系统来自系统妈:http://www.xitongma.com 系统概述 电脑公司ghost win7 x86(32位)万能装机版集成的软件符合电脑公司及电脑城装机绝大多数人要求及喜好,既大众,又时尚 ...
- Openjudge 2.5 6264:走出迷宫
总时间限制: 1000ms 内存限制: 65536kB 描述 当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单. 假设你已经得到了一个n* ...
- 成魔笔记1——先入IT,再成魔
关于我为什么要写这个博客的原因,做一个简单的解释.因为报考的一时兴起,我选择了软件专业.可是三年下来,感觉自己没做多少事,也没收获到多少东西.很多时候都是老师讲什么,都是完全陌生的东西,跟不上教学的思 ...
- 对于exacoin虚拟币以及其他虚拟币乱象的思考
今天晚上12点正,我帮两个朋友购买exacoin虚拟币,当然我也购买,为了购买我做了充分的准备,包括使用多个浏览器和准备良好的***代理,并转如足量BTC以支持购买,但是通过三天晚上的奋战,让我感觉这 ...
- 判断NumLock键和CapsLock键是否被锁定
实现效果: 知识运用: AIP函数GetKeyState //针对已处理过的按键 在最近一次输入信息时 判断指定虚拟键的状态 intkey:预测试的虚拟键键码 实现代码: [DllImport(&qu ...
- Swift 中 String 与 CChar 数组的转换
在现阶段Swift的编码中,我们还是有很多场景需要调用一些C函数.在Swift与C的混编中,经常遇到的一个问题就是需要在两者中互相转换字符串.在C语言中,字符串通常是用一个char数组来表示,在Swi ...
- A Fast and Easy to Use AES Library
http://www.codeproject.com/Articles/57478/A-Fast-and-Easy-to-Use-AES-Library Introduction EfAesLib i ...
- python--进程内容补充
一. 进程的其他方法 进程id, 进程名字, 查看进程是否活着(is_alive()), terminate()发送结束进程的信号 import time import os from multipr ...