[bzoj2288]【POJ Challenge】生日礼物_贪心_堆
【POJ Challenge】生日礼物
题目大意:给定一个长度为$n$的序列,允许选择不超过$m$个连续的部分,求元素之和的最大值。
数据范围:$1\le n, m\le 10^5$。
题解:
显然的一步转化,就是把连续的、同符号的元素求和变成一个。
这样就变成了一串正负号交替的序列。
现在把所有正数都加一起,如果满足条件就直接输出。
不满足的话,我们发现:
我们可以选取一个负数,这样可以合并左右两个正数。
我们也可以删掉一个正数。
以上两个操作,都会使我们的选取的个数$-\ -$。
至于到底应该怎么选呢?
就弄一个堆,每次拿出来代价最小的操作就好。
代码:
#include <bits/stdc++.h>
#define N 100010
using namespace std;
int a[N], b[N], nxt[N], pre[N];
bool vis[N];
char *p1, *p2, buf[100000];
#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
int rd() {
int x = 0, f = 1;
char c = nc();
while (c < 48) {
if (c == '-')
f = -1;
c = nc();
}
while (c > 47) {
x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
}
return x * f;
}
struct Node {
int val, id;
friend bool operator < (const Node &a, const Node &b) {
return a.val > b.val;
}
};
priority_queue<Node> q;
int main() {
int n = rd(), m = rd();
for (int i = 1; i <= n; i ++ ) {
b[i] = rd();
}
int n1 = 1;
a[1] = b[1];
for (int i = 2; i <= n; i ++ ) {
if ((a[n1] <= 0 && b[i] <= 0) || (a[n1] >= 0 && b[i] >= 0)) a[n1] += b[i];
else a[ ++ n1] = b[i];
}
if (a[n1] <= 0) {
n1 -- ;
}
if (a[1] <= 0) {
for (int i = 1; i < n1; i ++ ) {
a[i] = a[i + 1];
}
n1 -- ;
}
n = n1;
int ans = 0, sum = 0;
for (int i = 1; i <= n; i ++ ) {
if (a[i] > 0) {
sum ++ ;
ans += a[i];
}
Node mdl;
mdl.val = abs(a[i]);
mdl.id = i;
q.push(mdl);
nxt[i] = i + 1;
pre[i] = i - 1;
a[i] = abs(a[i]);
}
// cout << ans << endl ;
// cout << sum << endl ;
nxt[n] = pre[1] = 0;
if (sum <= m) {
cout << ans << endl ;
return 0;
}
m = sum - m;
for (int i = 1; i <= m; i ++ ) {
Node mdl = q.top();
q.pop();
while (vis[mdl.id] && !q.empty()) {
mdl = q.top();
q.pop();
}
// cout << mdl.val << endl ;
if (vis[mdl.id])
break;
ans -= mdl.val;
if (q.empty())
break;
int tmp = mdl.id;
if (!pre[tmp]) {
vis[tmp] = true;
vis[nxt[tmp]] = true;
pre[nxt[nxt[tmp]]] = 0;
}
else if(!nxt[tmp]) {
vis[tmp] = true;
vis[pre[tmp]] = true;
nxt[pre[pre[tmp]]] = 0;
}
else {
vis[nxt[tmp]] = true;
vis[pre[tmp]] = true;
mdl.val = a[tmp] = a[nxt[tmp]] + a[pre[tmp]] - a[tmp];
if (nxt[nxt[tmp]])
pre[nxt[nxt[tmp]]] = tmp;
if (pre[pre[tmp]])
nxt[pre[pre[tmp]]] = tmp;
pre[tmp] = pre[pre[tmp]];
nxt[tmp] = nxt[nxt[tmp]];
q.push(mdl);
}
}
cout << ans << endl ;
return 0;
}
小结:这玩意儿好像叫模拟费用流吧,不会不会有空学/cy
[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个了..显然没法优化 大概就会想到贪心乱搞了吧...一开始想贪心地通过几段小的负数把正 ...
- [bzoj2287][poj Challenge]消失之物_背包dp_容斥原理
消失之物 bzoj-2287 Poj Challenge 题目大意:给定$n$个物品,第$i$个物品的权值为$W_i$.记$Count(x,i)$为第$i$个物品不允许使用的情况下拿到重量为$x$的方 ...
- 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 ...
- [bzoj4345][POI2016]Korale_堆_贪心_线段树_dfs
bzoj4345 POI2016 Korale 题目链接:https://lydsy.com/JudgeOnline/problem.php?id=4345 数据范围:略. 题解: 由于$k$的范围问 ...
- poj 3253 Fence Repair 贪心 最小堆 题解《挑战程序设计竞赛》
地址 http://poj.org/problem?id=3253 题解 本题是<挑战程序设计>一书的例题 根据树中描述 所有切割的代价 可以形成一颗二叉树 而最后的代价总和是与子节点和深 ...
- [bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分
Exercise bzoj-2097 Usaco-2010 Dec 题目大意:题目链接 注释:略. 想法:题目描述生怕你不知道这题在考二分. 关键是怎么验证?我们想到贪心的删边. 这样的策略是显然正确 ...
- [bzoj4027][HEOI2015]兔子与樱花_贪心_树形dp
兔子与樱花 bzoj-4027 HEOI-2015 题目大意:每个点有c[i]朵樱花,有一个称重m, son[i]+c[i]<=m.如果删除一个节点,这个节点的樱花或移动到它的祖先中深度最大的, ...
随机推荐
- 【Python之路】特别篇--服务商API认证、Restful、一致性哈希
API加密方式 1/ 加密方式: Md5 (随机字符串 + 时间戳) 2/ 发送方式: http://127.0.0.1:8888/index?pid= MD5加密值 | 时间戳 | 序号 服务端接收 ...
- learning armbian steps(6) ----- armbian 源码分析(一)
为了深入学习armbian,前面已经学习了如何手动构建arm ubuntu rootfs. 由于armbian官方的文档比较的匮乏,所以最终还是决定通过其编译的过程来深入地学习. 为了快速度深入地学习 ...
- [Vue] : Vue实例的声明周期
vue实例的生命周期 什么是生命周期:从Vue实例创建.运行.到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期! 生命周期钩子:就是生命周期事件的别名而已: 生命周期钩子 = 生命周期函 ...
- oracle面试题2
1.题目要求 为管理岗位业务培训信息,建立3个表:S (S#,SN,SD,SA) S#,SN,SD,SA 分别代表学号.学员姓名.所属单位.学员年龄C (C#,CN ) C#,CN 分别代表课程编号. ...
- 1.4 JAVA日期处理
一.JAVA日期 参考链接:https://www.runoob.com/java/java-date-time.html 1.日期两个构造函数 1.第一个构造函数使用当前日期和时间来初始化对象.Da ...
- C#_类
1:访问修饰符 访问修饰符可以定义应用程序中类成员的作用域.和C++有一些不同,下面说明一下: public:访问不受限制,public成员可以被任何其他类访问. private:访问只限于包含该成员 ...
- Java项目服务器跨域设置
引入jar包 cors-filter-2.6 :http://central.maven.org/maven2/com/thetransactioncompany/cors-filter/2.6/co ...
- Linux设备驱动程序 之 装载和卸载模块
前置说明 本文例子中涉及两个模块hello.ko和world.ko,其中hello导出符号供world使用: insmod 该命令将模块的代码和数据装入内核,然后使用内核的符号表继续模块中任何未解析的 ...
- legend3---7、videojs的使用配置的启示是什么
legend3---7.videojs的使用配置的启示是什么 一.总结 一句话总结: 很多东西网上都有现成的,直接拿来用就好,效果是又快又好 1.用auth认证登录的时候报 "validat ...
- typescript简单的应用
简单来说typescript就是新增一下方法,以及增加类型判断 一.普通的类型判断 1.布尔类型(boolean) let isDone: boolean = false let createdByB ...