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

【题目描述:】

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

【输入格式:】

第一行,两个正整数n,k。

第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。

【输出格式:】

输出1个数,表示cyrcyr种树的最大获利。

输入样例#16 3 
100 1 -1 100 1 -1
输出样例#1200
输入输出样例

【算法分析:】

这时一道贪心的题目:

对于一个树坑i,有两种状态:种树或者不种树

当选择树坑i种树时,获利为a[i]

而也可以选择在(i - 1)和(i + 1)两个位置种树,所以将a[i]更新成a[i - 1] + a[i + 1] - a[i]

利用大根堆每次寻找最大值,并将更改后的值再次push进堆里

如果选择i后又选择了(i - 1)和(i + 1),更新时 - a[i]的操作就显得不可或缺了= =

利用堆优化后的算法复杂度为O(k log2 n)

【代码:】

 1 //种树
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<vector>
 7 
 8 #define pii pair<int, int>
 9 #define mkp make_pair
10 #define fi first
11 #define se second
12 using namespace std;
13 
14 const int MAXN = 500000 + 1;
15 
16 priority_queue<pii> q;
17 
18 int n, k;
19 int a[MAXN], l[MAXN], r[MAXN];
20 bool tree[MAXN];
21 long long ans;
22 
23 int main() {
24     scanf("%d%d", &n, &k);
25     for(int i = 1; i <= n; i++) {
26         scanf("%d", &a[i]);
27         q.push(mkp(a[i], i));
28         l[i] = i - 1, r[i] = i + 1;
29     }
30     r[0] = 1, l[n + 1] = n;
31     while(k--) {
32         while(tree[q.top().se]) q.pop();
33         pii tmp = q.top();
34         q.pop();
35         if(tmp.fi <= 0) break;
36         ans += tmp.fi;
37         int pos = tmp.se;
38         a[pos] = a[l[pos]] + a[r[pos]] - a[pos];
39         tmp.fi = a[pos];
40         tree[l[pos]] = tree[r[pos]] = 1;
41         l[pos] = l[l[pos]], r[l[pos]] = pos;
42         r[pos] = r[r[pos]], l[r[pos]] = pos;
43         q.push(tmp);
44     }
45     printf("%lld\n", ans);
46 }

猜你喜欢

转载自www.cnblogs.com/devilk-sjj/p/9031358.html