洛谷 P1484 种树
Description
- cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。
Input
第一行,两个正整数n,k。
第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。
Output
- 输出1个数,表示cyrcyr种树的最大获利。
Sample Input
6 3 100 1 -1 100 1 -1
Sample Output
200
Data Size
对于20%的数据,n<=20。
对于50%的数据,n<=6000。
对于100%的数据,n<=500000,k<=n/2,在一个地方种树获利的绝对值在1000000以内。
题解:
- 这题跟数据备份这题原理相同。都是利用数学归纳法。
#include <iostream>
#include <cstdio>
#include <set>
#define N 500005
#define int long long
using namespace std;
struct Node
{
int pos, val;
friend bool operator < (Node x, Node y) {
if(x.val == y.val) return x.pos < y.pos;
return x.val > y.val;
}
};
int n, k, ans;
int a[N], l[N], r[N];
set<Node> st;
int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return x *= f;
}
signed main()
{
cin >> n >> k;
for(int i = 1; i <= n; i++)
{
a[i] = read();
st.insert((Node){i, a[i]});
l[i] = i - 1, r[i] = i + 1;
}
a[0] = a[n + 1] = -0x3f3f3f3f;
for(int i = 1; i <= k; i++)
{
int val = (*st.begin()).val;
int pos = (*st.begin()).pos;
if(val <= 0) {cout << ans; return 0;}
ans += val;
//删掉堆中的pos和l[pos]和r[pos]
st.erase(st.begin());
st.erase((Node){l[pos], a[l[pos]]});
st.erase((Node){r[pos], a[r[pos]]});
//添加新元素
a[pos] = a[l[pos]] + a[r[pos]] - a[pos];
st.insert((Node){pos, a[pos]});
l[pos] = l[l[pos]], r[l[pos]] = pos;
r[pos] = r[r[pos]], l[r[pos]] = pos;
}
cout << ans;
return 0;
}