原题链接:蓝桥杯算法提高VIP-种树
解题思路:
这道题开始以为是dp,后来发现如果这样做就会炸空间啊!
于是采用贪心。思路非常神奇。
就是以在每个坑种树的收益建一个大根堆
然后用链表存它的前驱后继(n的后继为1,1的前驱为n)
每次取最大的收益。
那么问题来了————有可能在这个点种树比在它两边各种一棵树收益小。
但一定是两边各种一棵,因为我们建的是大根堆,先出来的一定大。
所以我们可以选这个坑种树,也可以选两边的坑各种一棵,所以我们给我们的贪心一个反悔的机会
就是选在这个坑种树以后将它两边的坑合并为一个价值为(w[l]+w[r]-w[now])的坑,代替我们选择的坑
这里非常的巧妙,就是如果选了这个坑就相当于不在那个中间的坑种树了,而是在它两边各种一棵。
然后放一下丑陋的代码
注意事项:
参考代码:
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<queue> # define M (200000+50) using namespace std; struct node{ int value,place; friend bool operator < (node x,node y) { return x.value < y.value; } }; priority_queue<node> q; int n,m,Ans,chose,nxt[M],pre[M],w[M],l,r; bool vis[M];void change(int x){ vis[x]=1; nxt[pre[x]]=nxt[x]; pre[nxt[x]]=pre[x]; nxt[x]=0; pre[x]=0; }int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&w[i]); } if((n>>1)<m){ cout<<"Error!"<<endl; return 0; } for(int i=1;i<n;i++) nxt[i]=i+1; nxt[n]=1; for(int i=2;i<=n;i++) pre[i]=i-1; pre[1]=n; for(int i=1;i<=n;i++) q.push((node){w[i],i}); for(int i=1;i<=m;i++) { while(vis[q.top().place]) q.pop() ; node temp = q.top(); q.pop(); Ans+= temp.value; l=pre[temp.place]; r=nxt[temp.place]; w[temp.place]=w[l]+w[r]-w[temp.place]; change(l); change(r); q.push((node){w[temp.place],temp.place}); } printf("%d\n",Ans); return 0; }
0.0分
3 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复