原题链接:蓝桥杯算法提高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、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复