• 题解 P1484 种树


    题目

    传送门

    cyrcyr今天在种树,他在一条直线上挖了 n 个坑。
    这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。
    而且由于cyrcyr的树种不够,他至多会种 k 棵树。
    假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

    思路

    开始没有想到,这是一道可以反悔的贪心题。

    我们可以用大根堆来维护最大获利的树,用链表来维护每棵树左右的树。

    每次选择了最大的树,我们要把此树左右两边 vis 标记为1,下次枚举到vis[x] = 1continue

    但有可能选左右两颗树比选中间这颗树情况更优,于是我们要在加入一颗树,值为 左树权值+右树权值-中间树权值。

    这样,在下一次枚举时,当我们选了这颗树,则答案增加了 左树权值+右树权值-中间树权值+中间树权值 = 左树权值+右树权值。 正好选择了2颗树。

    注意:不一定要种满 k 颗树

    代码

    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    #include <string>
    
    #define ll long long 
    #define mes(x) memset(x,0,sizeof(x))
    #define re(x) read(x)
    #define il inline
    
    using namespace std;
    
    template <typename T>
    il void read(T &x){
    	x = 0; T sgn = 1; char ch = getchar();
    	for(;!isdigit(ch);ch = getchar()) if(ch=='-') sgn = -1;
    	for(;isdigit(ch);ch = getchar()) x = (x<<1)+(x<<3)+(ch^48);
    	x *= sgn;
    }
    
    template <typename T>
    il void write(T x){
    	if(x < 0) x = -x,putchar('-');
    	if(x == 0) putchar(48);
    	int cnt = 0, a[70];
    	while(x > 0){
    		a[++cnt] = x%10;
    		x /= 10;
    	}
    	for(int i = cnt;i > 0;i--){
    		putchar(a[i]+48);
    	}
    	putchar('
    ');
    }
    
    const int MAXN = 5e5+10;
    
    int n,k,a[MAXN];
    bool vis[MAXN];
    ll ans = 0,tot = 0;
    
    struct tree{
    	int pos;
    	ll val;
    	bool operator < (const tree &b) const {
    		return val < b.val;
    	}
    }tr[MAXN];
    
    struct place{
    	int l,r;
    	ll val;
    }p[MAXN];
    
    priority_queue <tree> q;
    
    il void Del(int x){
    	p[x].l = p[p[x].l].l;
    	p[x].r = p[p[x].r].r;
    	p[p[x].l].r = x;
    	p[p[x].r].l = x;
    }
    int main (){
    	re(n);re(k);
    	for(int i = 1;i <= n;i++){
    		re(a[i]);
    		p[i].l = i-1;
    		p[i].r = i+1;
    		p[i].val = a[i];
    		q.push((tree){i,a[i]});
    	}
        for(int i = 0;i < k;i++){
        	int x = q.top().pos; q.pop();
        	if(vis[x]) {
        		i--;
        		continue;
        	}
        	vis[p[x].l] = vis[p[x].r] =1;
    		tot += p[x].val;
    		ans = max(tot,ans);
    		p[x].val = p[p[x].l].val + p[p[x].r].val - p[x].val;
    		q.push((tree){x,p[x].val});
    		Del(x);
    	}
    	write(ans);
    	return 0;
    } 
    
  • 相关阅读:
    name mangling
    Haskell: What is Weak Head Normal Form
    取模运算和取余运算的区别
    a common method to rotate the image
    代码静态分析工具
    LeeCode-Single Number III
    七夕这天
    mysql TO_DAYS()
    (转)剖析Linux文件编码的查看及修改
    docker
  • 原文地址:https://www.cnblogs.com/werner-yin/p/13303569.html
Copyright © 2020-2023  润新知