[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.如果删除一个节点,这个节点的樱花或移动到它的祖先中深度最大的, ...
随机推荐
- learning gcc #pragma once
referenc: https://zh.wikipedia.org/wiki/Pragma_once 在C和C++编程语言中,#pragma once是一个非标准但是被广泛支持的前置处理符号, 会让 ...
- 多线程中volatile关键字的作用
原文链接:https://blog.csdn.net/xuwentao37x/article/details/27804169 多线程的程序是出了名的难编写.难验证.难调试.难维护,这通常是件苦差事. ...
- Python: 关于 sys.stdout.flush()
stackoverflow https://stackoverflow.com/questions/10019456/usage-of-sys-stdout-flush-method Python's ...
- python 显示!到~的字符
count = ): != : print(chr(i),end=" ") else: print(chr(i)) count += 输出 ! " # $ % & ...
- CF427D
CF427D SA的奇技淫巧,其实就是板子. 题意: 给定两个字符串,求最短的满足各只出现一次的连续公共字串 解析: 一般情况下,SA都是用来求最长公共前缀的,好像和这道题所求的最短公共子串没有任何关 ...
- Java后台开发精选知识图谱
1.引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习方 ...
- in和exists的区别
表展示 首先,查询中涉及到的两个表,一个user和一个order表,具体表的内容如下: user表: order表: in 确定给定的值是否与子查询或列表中的值相匹配.in在查询的时候,首先查询子查询 ...
- .net 数据导出
安装npoi,下面是具体的C#代码: public static XSSFWorkbook BuildWorkbook(DataTable dt) { var book = new XSSFWorkb ...
- 深度学习变革视觉计算总结(CCF-GAIR)
孙剑博士分享的是<深度学习变革视觉计算>,分别从视觉智能.计算机摄影学和AI计算三个方面去介绍. 他首先回顾了深度学习发展历史,深度学习发展到今天并不容易,过程中遇到了两个主要障碍: 第一 ...
- [Java]用 MessageFormat 拼接组合字符串
package com.hy; import java.text.MessageFormat; public class Test3 { public static void main(String[ ...