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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值