Jzoj4726 种花

来源:互联网 发布:淘宝网十字绣鞋垫 编辑:程序博客网 时间:2024/04/30 05:13

相信大家都猜到题意了,简单说一下

圆形广场共有 N 个种花的位置,顺时针编号1到N。并且每个位置都有一个美观度ai ,两株花不能种在相邻的位置(1号和N号也算相邻位置)一共有 M 株花,现在小D也想知道应该如何摆这 N 株花才能使美观度最大

这道题显然可以用堆,每次将堆顶最大的元素取出并删除两边的元素

但是正确性显然有问题,比如10,11,10,1显然答案是20而不是12

那么每次,我们取出一个节点i后,要向堆里增加一个“撤回”节点,其位置i不变,但是值v[i]变为v[i-1]+v[i+1]-v[i],同时删除i-1,i+1两个节点,这样的话,我们就需要一个双向链表来维护左右节点是否被选择,l[i]表示i左边第一个没有备选的节点,r[i]类似

流程:

1.取出节点(i,v[i])

2.删除l[i],r[i],并将l[l[i]]以及r[r[i]]与i相连

3.向堆里加入节点(i,v[l[i]]+v[r[i]]-v[i]),那么如果取出这个节点,就相当于放弃i,而改为选择l[i]和r[i]

#pragma GCC optimize("O3")#pragma G++ optimize("O3")#include<stdio.h>#include<string.h>#include<algorithm>#include<queue>using namespace std;struct flower{ int id,x; };inline bool operator < (flower a,flower b){ return a.x<b.x; }int l[200010],r[200010],d[200010],w[200010],n,m,ans=0;priority_queue<flower> q;int main(){scanf("%d%d",&n,&m);if(n<m*2) return 0&puts("Error!");for(int x,i=0;i<n;++i){scanf("%d",&x);q.push((flower){i,w[i]=x});l[i]=(i-1+n)%n;r[i]=(i+1)%n;}for(int i=0,j;i<m;++i){flower a=q.top(); q.pop();if(d[j=a.id]){ --i; continue; }ans+=a.x; q.push((flower){j,w[j]=(w[l[j]]+w[r[j]]-a.x)});r[l[l[j]]]=j; l[r[r[j]]]=j;d[l[j]]=1; d[r[j]]=1;l[j]=l[l[j]]; r[j]=r[r[j]];}printf("%d\n",ans);}

原创粉丝点击