1. 程式人生 > >(堆)P1484 種樹

(堆)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;
}