P1484 种树 - 堆 - 贪心

这题想得脑阔疼。。。我只想到可以选一个点,或者不选这个点选其左右两个点的和

先来特殊情况,k=1, 然后k=2
可以发现由1到2的过程中,可以是一个本来被选的点,替换为他左右两边的点,收益增加了a[pos+1] + a[pos-1] - a[pos]
这个题是一个个选,直到选了k个,有种递推的感觉,先确定种了前面几个,再确定这一个该怎么种

然后我不会处理若有别的点也选上,并且影响到这个pos+1和pos-1的情况

事实上可以把这三个点缩在一起啊(当然不能提前缩,要在pos这个点被选时缩起来)
然后我若再选一个别的点,若这个别的点会影响到pos+1或pos-1,因为缩了点,pos+1和pos-1现在都在pos上,所以这个“别的点”就会让pos的值不可用,由于我们把值也缩在pos上了,直接导致这个pos替换为pos+1和pos-1不可用了,这也符合题意,并且更好写
但是还是有点难处理怎么缩点,缩点之后应当删除3个点,新建一个点,而原来其他位于这三个点左边最靠右的点,若我们选了这个点,这说明这三个点就不可选了,也就是新点不可选,所以要把原来位于左边最靠右的点的右边连到新点上,这就需要开几个数组模拟链表什么的了

堆的题拆点(一个点拆成两个,可以是等大的两个,对左右两边起一个桥梁作用)和缩点(删点)比较多

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 1000000 + 10;
typedef long long ll;
ll n,k,a[MAXN],ans,flg[MAXN],cnt,l[MAXN],r[MAXN];
bool fina;
struct node{
    int val, pos;
    bool operator < (const node & a) const {
        return val < a.val;
    }
};
priority_queue<node> q;
int main() {
    scanf("%lld%lld", &n, &k);
    for(int i=1; i<=n; i++) {
        scanf("%lld", &a[i]);
        l[i] = i-1;
        r[i] = i+1;
        q.push((node){a[i], i});
    }
    int tot = n;
    while(!q.empty()) {
        node now = q.top();
        q.pop();
        if(now.val <= 0) break;
        int pos = now.pos;
        if(flg[pos]) continue;
        if(++cnt > k) break;
        ans += now.val;
        a[++tot] = a[l[pos]] + a[r[pos]] - a[pos];
        flg[pos] = flg[r[pos]] = flg[l[pos]] = 1;
        l[tot] = l[l[pos]], r[tot] = r[r[pos]];
        r[l[tot]] = tot;
        l[r[tot]] = tot;
        q.push((node){a[tot], tot});
    }
    printf("%lld", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Zolrk/p/9785086.html

时间: 2024-10-08 20:44:51

P1484 种树 - 堆 - 贪心的相关文章

POJ3253 Fence Repair 小顶堆+贪心

给了你N个木棒,求把他们组装成一根需要的最小花费,每次只能选两根组装在一起,需要的花费为两个木棒之和, 以前遇到过把一整根切开的,那个是DP,这个则有些类似,可是大胆的猜测了一下,直接每次选取所有木棒中最短的两根,这样就可以了,那么贪心是适用的,但是数量很多,而且两根最短的组装好了得插回去,这样不可能每次都排序吧, 这题首先优先队列肯定是可以做的, 最小堆也是可以的,每次都选出堆里的最小的两个求和再放回去即可 队列本身也就是堆吧,所以差别不大,但是没用过最小堆最大堆的 所以用一次把 #inclu

P4053 [JSOI2007]建筑抢修 堆贪心

思路:堆贪心 提交:1次 题解: 先按时间\(sort\),然后如果能修就直接扔堆里,不能修取堆顶比一下时间长短,把时间短的扔进堆: #include<cstdio> #include<iostream> #include<queue> #include<algorithm> #define ull unsigned long long #define ll long long #define R register int using namespace s

【洛谷】【堆+贪心】P1484 种树

[题目描述:] cyrcyr今天在种树,他在一条直线上挖了n个坑.这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树.而且由于cyrcyr的树种不够,他至多会种k棵树.假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利. [输入格式:] 第一行,两个正整数n,k. 第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利. [输出格式:] 输出1个数,表示cyrcyr种树的最大获利. 输

P1484 种树(堆)

堆优化的贪心,考虑种一棵树的最大收益,种了当前树两旁的树之后的收益为a[i-1]+a[i+1]-a[i] 用双向链表维护住左右关系,大根堆则可以“反悔”,维护另一个记录某个坑能不能种树的数组即可 代码: #include <bits/stdc++.h> #define int long long #define sc(a) scanf("%lld",&a) #define scc(a,b) scanf("%lld %lld",&a,&am

【BZOJ 2151】 2151: 种树 (贪心+堆)

2151: 种树 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度.但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置.值得注意的是1号和n号也算相邻位置!).最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大.如果无法将m棵树苗

bzoj 2151: 种树【贪心+堆】

和数据备份差不多 设二元组(i,a[i]),开一个大根堆把二元组塞进去,以len排序,每次取出一个二元组 因为单纯的贪心是不行的,所以设计一个"反悔"操作. 记录二元组的前驱pr后继ne,把拿出来的二元组的len加进答案,然后把当前二元组和它的前驱后继当成一个,也就是len[x]=a[pr[x]]+a[ne[x]]-a[x],相应修改前驱后继,然后"删掉"前驱后继的二元组,这样的意思是如果再次选了修改过的二元组x,就意味着退还掉x,选择它的前驱后继,易证这样个数和a

BZOJ 2802 Poi2012 Warehouse Store 堆+贪心

题目大意:有n天,早上进货中午卖,可以选择卖或者不卖,问最多可以卖出多少人 首先贪心的思想是如果当前能卖就卖 但是这样不一定是最优的 比如说我第一天来一个人把所有的库存都买走了 然后后面基本没有补给 后面的人都饿死了 因此我们维护一个大根堆来记录我们都卖出了多少份 如果有一个人买不到 我们去大根堆里寻找有没有买的比他多的 如果有 把之前的人取消 卖给这个人 这样虽然不能增加答案 但是可以增加库存 #include <cstdio> #include <cstring> #inclu

BZOJ1826 [JSOI2010]缓存交换 堆 贪心

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1826 题意概括 Cache中有m个储存单元,接下来有n个访问地址,每个地址用一个数字表示.访问每一个地址,就要使用一次Cache的一个储存单元,当你选择某一个储存单元时,如果这个储存单元原来不是该地址,那么就发生一次遗失,并把该储存单元的值改为该地址:如果原来这个储存单元就是这个地址,那么不发生遗失且可以直接访问该地址.现在有n个地址访问请求依次输入,每次,你可以选择把地址放在哪一个存储单元,求

BZOJ 1029: [JSOI2007]建筑抢修 堆+贪心

1029: [JSOI2007]建筑抢修 Description 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏.现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间.同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑.如果某个建筑在一段时间之内没有完全修理完毕,这