P1484 种树 (贪心+堆+双向链表)

题意:

在这里插入图片描述
在这里插入图片描述

解法:

题意其实就是n个数取出最多m个,满足取出的不相邻,求最大值.

如果第1个数选择a[i],那么a[i-1]和a[i+1]不能取.
当要取第2个数时,要么取除了a[i-1],a[i],a[i+1]外的数,
要么讲a[i]改成取a[i-1]和a[i+1]这两个数.

取其中的max,那么其实我们可以这样做,
取出a[i]的时候,在丢入一个a[i-1]+a[i+1]-a[i],
和其他数一起放在堆中,然后堆顶就是下一步要取的位置.

如果我们把a[i]换成了a[i-1]和a[i+1],
那么要加入的就是a[i-2]+a[i]+a[i+2]-(a[i-1]-a[i+1]).
发现每次都需要当前数左边和右边的数的下标,
用l[i]和r[i]做一个双向链表存当前数左边和右边的第一个未取数即可.

code:

#include <bits/stdc++.h>
#define int long long
#define PI pair<int,int>
using namespace std;
const int maxm=2e6+5;
int mark[maxm];
int a[maxm];
int l[maxm];
int r[maxm];
int n,m;
signed main(){
    
    
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    
    
        cin>>a[i];
        l[i]=i-1;
        r[i]=i+1;
    }
    priority_queue<PI,vector<PI>,less<PI> >q;
    for(int i=1;i<=n;i++){
    
    
        q.push({
    
    a[i],i});
    }
    int ans=0;
    while(m--){
    
    
        PI x=q.top();q.pop();
        while(mark[x.second]){
    
    
            x=q.top();q.pop();
        }
        if(x.first<0)break;
        ans+=x.first;
        int p=x.second;
        mark[l[p]]=mark[r[p]]=1;
        a[p]=a[l[p]]+a[r[p]]-a[p];
        q.push({
    
    a[p],p});
        //
        l[p]=l[l[p]];
        r[p]=r[r[p]];
        r[l[p]]=p;
        l[r[p]]=p;
        //
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/114951162
今日推荐