【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; }