LG1484 种树

题意

\(N\)个数,至多选\(k\)个,相邻两数不能同时选,问最大价值。

思路

一种假的思路:直接扔进对里面,每次都选最大的可以选的,再把两边和自己标记为不能选,一直贪心下去。是不是很有道理?
假在哪里?虽然这个是最大的,旁边两个加起来比它大,就错了。
把这个假贪心改一改,赐予它一个反悔的机会。如果它不选\(i\),那么它可以选则\(last[i]\)\(next[i]\),这两个一定是一起选的(因为在一起才有超过\(i\)的可能)。此时它的价值为\(a[last[i]]+a[next[i]]\),原先已经选了\(a[i]\),所以就再扔一个\(a[last[i]]+a[next[i]]-a[i]\) 进去取代原来的数。由于这样选了\(2\)个数,而选一次反悔一次也恰好用掉\(2\)次机会,所以正好。
置于维护\(last、next\)只要用双向链表就好了

#include <bits/stdc++.h>
using namespace std;
pair<int,int> t;
const int N=500005;
int n,k,a[N],f[N],last[N],Next[N];
long long ans;
priority_queue <pair<int,int>> q;
int main(){
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        q.push(make_pair(a[i],i));
    }
    for (int i=1;i<=n;i++) last[i]=i-1,Next[i]=i+1;
    last[n+1]=n,Next[0]=1;
    for (int i=1;i<=k;i++){
        t=q.top();
        while (f[t.second]) q.pop(),t=q.top();
        q.pop();
        if (t.first<0) break;
        ans+=t.first;
        int id=t.second;
        f[last[id]]=f[Next[id]]=1;
        a[id]=a[last[id]]+a[Next[id]]-a[id];
        q.push(make_pair(a[id],id));
        last[id]=last[last[id]],Next[id]=Next[Next[id]];
        Next[last[id]]=id,last[Next[id]]=id;
    }
    printf("%lld",ans);
}

猜你喜欢

转载自www.cnblogs.com/flyfeather6/p/10632781.html