题目类型:堆+贪心

传送门:>Here<

题意:有\(N\)个坑,每个坑可以种树,且获利\(a[i]\)(可以为负)。任何相邻两个坑里不能都种树,问在最多种\(K\)棵树的前提下的最大获利

解题思路

第一眼觉得是\(DP\),但是数据太大\(NK\)显然不行……

如果不约束相邻两个坑不能都种,那么显然是取最大的几个正数。只需排序求解即可

回到问题,一步一步分析吧。

假设\(K=1\),那么此时必然选最大的。

假设\(K=2\),可以选择最大的\(a[i]\),并且对于所有\(j \neq i-1 且 j \neq i+1\),选择\(a[j]\)。但是存在一个问题,加入存在这样的情况:\(99 \ 100 \ 99\)。因此还有可能的最优方案是不选择\(a[i]\),选取\(a[i-1]和a[i+1]\)。并且我们会发现,出现这种情况时,必定同时选择\(a[i-1]和a[i+1]\),因为\(a[i]\)才是最大的

由于这种情况的存在,普通的做法似乎毫无头绪。联系网络流中我们引入了反向边的思想,意在反悔之前作出的决策。那么放在本题也一样。我们先去选择那个最大的,然后通过一种方式消除影响后选择两边的。于是,我们可以用一个大根堆维护所有的坑,选出最大的以后,删除最大值\(a[i]\),并推入\(p=a[i-1]+a[i+1]-a[i]\)。如果\(p>0\),意味着\(a[i-1]+a[i+1]>a[i]\)。

但是注意,并不是每次碰到这种情况我们都要去选,毕竟选择\(a[i]\)只需要一颗树,而选择\(a[i-1]+a[i+1]\)要两棵树。因此依然按照大根堆的规定来行使。容易发现,在堆里,我们不仅需要存值,还需要存位置

下一步,如何实现?这是个比较困难的问题,在此之前还需要对问题进行深入分析

前面我们得到结论,要么选择\(a[i]\),要么选择\(a[i-1]+a[i+1]\)。这就好像\(a[i-1] .. a[i+1]\)是一个节点一样,初始值是\(a[i]\),选过之后值成为了\(a[i-1]+a[i+1]-a[i]\)。并且我们也会发现,选择两边的节点的话将会导致\(a[i-2]和a[i+2]\)也不能选,正好像一个节点两侧的节点一样。

联系缩点的思想,选择完一次以后,就可以将其左右缩点。此后这个点的权值就变了,但是依然是个正常的点。我们维护数组\(L[i]和R[i]\)表示点\(i\)的左右侧(缩点之后)。初始时\(L[i]=i-1, R[i]=i+1\)。每一次缩点之后往左右两侧拓展即可。当然,切不可用\(i-1\)来代替左右侧,因为此时我们考虑的点全都得当成是缩完之后的点

注意,缩点以后这个点内部的原先点的个数一定是奇数个。因此我们把信息全部存在中间那个点上,并且不允许访问那些其他被缩掉的点。用布尔数组记录,如果大根堆的堆顶访问到的是已经被标记过的则强行弹出。如果遇到负数的则意味着再选下去肯定不会优,直接结束。

Code

已压行

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
using namespace std;
typedef long long ll;
const int MAXN = 500010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
struct Tree{ ll val; int idx; };
inline bool operator < (const Tree& a, const Tree& b){ return a.val < b.val; }
int N,K,x,used[MAXN],L[MAXN],R[MAXN]; ll ans,a[MAXN];
priority_queue <Tree> q;
int main(){
N = r, K = r;
for(int i = 1; i <= N; ++i){ q.push((Tree){a[i]=r, i}); L[i] = i-1, R[i] = i+1; }
while(K--){
while(used[q.top().idx]) q.pop();
if(q.top().val <= 0) break;
ans += 1LL * q.top().val, x = q.top().idx; q.pop();
a[x] = a[L[x]] + a[R[x]] - a[x];
used[L[x]] = used[R[x]] = 1;
L[x] = L[L[x]], R[L[x]] = x; R[x] = R[R[x]], L[R[x]] = x;
q.push((Tree){1LL * a[x], x});
}
printf("%lld", ans);
return 0;
}

[洛谷P1484] 种树的更多相关文章

  1. 洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)

    洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/132 ...

  2. 洛谷 P1484 种树

    题目描述 cyrcyr今天在种树,他在一条直线上挖了n个坑.这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树.而且由于cyrcyr的树种不够,他至多会种k棵树 ...

  3. 洛谷 P1484 种树 题解

    题面 这是一道标准的带反悔贪心: 利用大根堆来维护最大值: 当选择了num[i]后,反悔了,反之选择选了num[i-1]和num[i+1]时获利便增加了num[i-1]+num[i+1]-num[i] ...

  4. 洛谷 P1484 种树(优先队列,贪心,链表)

    传送门 解题思路 第一眼的贪心策略:每次都选最大的. 但是——不正确! 因为选了第i个树,第i-1和i-1棵树就不能选了.所以,要有一个反悔操作. 选了第i个后,我们就把a[i]的值更新为a[l[i] ...

  5. Guard Duty (medium) Codeforces - 958E2 || (bzoj 2151||洛谷P1792) 种树 || 编译优化

    https://codeforces.com/contest/958/problem/E2 首先求出N个时刻的N-1个间隔长度,问题就相当于在这些间隔中选K个数,相邻两个不能同时选,要求和最小 方法1 ...

  6. 洛谷P1250种树(贪心)

    题目描述 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号成1..N.每个部分为一个单位尺寸大小并最多可种一棵树.每个居民想在门前种些树并指定了三个号码B,E, ...

  7. Java实现洛谷P1250 种树 (暴力)

    P1250 种树 输入输出样例 输入 9 4 1 4 2 4 6 2 8 9 2 3 5 2 输出 5 PS: 我种最少的树,意味着我的树要最多的被利用,意味着,我的树要尽可能的靠中间种, 也就是我把 ...

  8. HDU 1384 Intervals &洛谷[P1250]种树

    差分约束 差分约束的裸题,关键在于如何建图 我们可以把题目中给出的区间端点作为图上的点,此处应注意,由于区间中被标记的点的个数满足区间加法,这里与前缀和类似,对于区间[L..R]来说,我们加入一条从L ...

  9. 题解——洛谷P1250 种树(差分约束)

    一道看一眼就知道差分约束的题目 但是最短路spfa的时候注意松弛条件是 if(dis[u]+w[i]<dis[v[i]]) dis[v[i]]=dis[u]+w[i]; 不能写成 if(dis[ ...

随机推荐

  1. asp.net core C#设计一个实用的线程池

    菜菜呀,我最近研究技术呢,发现线上一个任务程序线程数有点多呀 CEO,CTO,CFO于一身的CXO x总,你学编程呢? 菜菜 作为公司总负责人,我以后还要管理技术部门呢,怎么能不会技术呢 CEO,CT ...

  2. NLP是什么

    NLP是什么 而在计算机领域, NLP(Natural Language Processing),也就是人们常说的「自然语言处理」,就是研究如何让计算机读懂人类语言. 这包括,既要能让计算机理解自然语 ...

  3. Glad to see you! CodeForces - 810D (交互+二分)

    This is an interactive problem. In the output section below you will see the information about flush ...

  4. git在vs2017中的使用

    对于习惯了右键提交源代码的道友来说,敲命令行真的蓝瘦香菇.所幸17里集成了Git插件,用起来还是挺方便的. 1.本地安装git,工具还是要有的,主要用于配置环境,ssh配置一下.就不用每次都去连接了. ...

  5. Python_内置函数之zip

    zip函数用于将可迭代的对象作为参数,将对象中的元素打包成一个个元祖,然后返回这些元祖组成的列表.如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同. l1 = [1, 2, 3] l2 ...

  6. Python之字符串格式化

    1)     占位符%s: %s是通用的占位符,所有类型不管是string还是int还是float全都代表. 如果使用%d,则只能代表整数:如果是%f,则只能代表小数: 2)     直接用加号+连接 ...

  7. 并发包学习之-atomic包

    一,模拟并发代码: 线程不安全的代码 //并发模拟代码 public class CountExample { //请求总数 public static int clientTotal = 5000; ...

  8. 【问题解决方案】之 关于某江加密视频swf专用播放器仍无法播放的问题

    前言: 从pt上下载了一些语言学习的视频之后一直打不开,百度谷歌了若干种方法仍然无解.无奈放弃. 某日从百度知道里又看到一个方法,试了一下,居然灵了.呜呼哀哉.赶紧记下来. 原方法链接:https:/ ...

  9. Python爬虫——用BeautifulSoup、python-docx爬取廖雪峰大大的教程为word文档

    版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com 廖雪峰大大贡献的教程写的不错,写了个爬虫把教程保存为word文件,供大家方便下载学习:http://p ...

  10. babel (二) update to v7

    一.rootmode In 7.1, we've introduced a rootMode option for further lookup if necessary. 二.Remove prop ...