【题目描述:】
cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。
【输入格式:】
第一行,两个正整数n,k。
第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。
【输出格式:】
输出1个数,表示cyrcyr种树的最大获利。
输入样例#1: 6 3 100 1 -1 100 1 -1 输出样例#1: 200
输入输出样例
【算法分析:】
这时一道贪心的题目:
对于一个树坑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 }
原文地址:https://www.cnblogs.com/devilk-sjj/p/9031358.html
时间: 2024-10-08 20:45:01