(堆)P1484 种树

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

看到题目第一想法是dp,发现dp数组开不了这么大
看题解,大佬真的太强辣
每次如果a[i]是最大值,那么就不能选a[i - 1]和a[i + 1],则删掉a[i - 1]和a[i + 1],新添一个点为a[i - 1] + a[i + 1] - a[i]相当于反悔选择a[i]而选择a[i - 1]和a[i + 1]将a[i]的影响去掉,不能单选a[i - 1]和a[i + 1]中的一个是因为a[i]权值最大,只有a[i - 1]和a[i + 1]同时选才可能更优,贪心策略。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 500000 + 7;
ll a[maxn], l[maxn], r[maxn];
struct node {
    ll v;
    int id;
    bool operator <(node b) const {
        return v < b.v;
    }
} t;
bool flag[maxn];
priority_queue<node> q;
int main()
{
    int n, k;
    cin >> n >> k;
    for(int i = 1; i <= n; i++) {
        cin >> t.v;
        a[i] = t.v;
        l[i] = i - 1;
        r[i] = i + 1;
        t.id = i;
        q.push(t);
    }
    r[0] = 1;
    l[n] = n + 1;
    ll ans = 0;
    while(k--) {
        while(flag[q.top().id]) q.pop();
        t = q.top();
        if(t.v < 0) break;
        q.pop();
        ans = ans + t.v;
        ll x = t.id;
        flag[l[x]] = flag[r[x]] = 1;
        a[x] = a[l[x]] + a[r[x]] - a[x];
        t.v = a[x];
        t.id = x;
        l[x] = l[l[x]];
        r[x] = r[r[x]];
        r[l[x]] = x;
        l[r[x]] = x;
        q.push(t);
    }
    cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/84479378
今日推荐