【JZOJ4726】种花 题解(贪心+堆)

题目大意:在一个长度为$n$的环型序列中取出$m$个数使这$m$个数的和最大,且要求这$m$个数互不相邻。

----------------------

考虑维护$nxt$和$lst$,即一个数的前驱和后继。如果此数被选中,那么$a[now]=a[lst]+a[nxt]-a[now]$并且更新前驱和后继,再将更新过后的数扔入堆中。

反悔机制。

操作$m$次后输出$ans$即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,m,a[maxn],nxt[maxn],lst[maxn],ans,mov[maxn];
struct node{int k;};
bool operator < (node x,node y) {return a[x.k]<a[y.k];};
priority_queue<node> q;
int main()
{
    scanf("%d%d",&n,&m);
    if (n<m*2)
    {
        printf("Error!");
        return 0; 
    } 
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),q.push((node){i});
    for (int i=1;i<n;i++) nxt[i]=i+1;nxt[n]=1;
    for (int i=2;i<=n;i++) lst[i]=i-1;lst[1]=n;
    while(m--)
    {
        node now=q.top();q.pop();
        while(mov[now.k])
        {
            now=q.top();
            q.pop();
        }
        ans+=a[now.k];
        a[now.k]=a[lst[now.k]]+a[nxt[now.k]]-a[now.k];
        mov[lst[now.k]]=1;
        mov[nxt[now.k]]=1;
        lst[now.k]=lst[lst[now.k]],nxt[lst[now.k]]=now.k;
        nxt[now.k]=nxt[nxt[now.k]],lst[nxt[now.k]]=now.k;
        q.push((node){now.k});
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2020-05-01 21:29  我亦如此向往  阅读(299)  评论(0编辑  收藏  举报