题目链接:https://www.luogu.com.cn/problem/P1484
一开始看到这题,想到用DP来做,但是n<=50,000(实在是太大了)。所以就换个思路,贪心。
假设 k=1 即只种一棵树,那肯定种盈利最大的那个,设为 i ,盈利为a[i]。
若 k=2 要种两颗树了,此时我们只有两种选择,种 i 以及和它不相邻的那个坑,或者种 i 左右的两坑,即 i-1 与 i+1。因为,如果只种左右俩坑其中一个,肯定盈利比a[i]小,因为a[i]是一开始选得最大的那个。
有了这个结论,我们就可以合并 i-1 与 i+1。建一个大根堆,每次取出最大的那个,然后合并它的左右坑,使a[i]=a[i+1]+a[i-1]-a[i],重新入堆,如果已种了k个树或者再种盈利为负,就结束。
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
struct node
{
int id;
ll value;
friend bool operator < (node a,node b)
{
return a.value < b.value;
}
};
priority_queue<node>q;
bool vis[maxn];//判断是否被合并
ll a[maxn];//每个坑种树的盈利
int l[maxn],r[maxn];//每个坑的左右
int n,k;
ll ans;
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
l[i]=i-1;
r[i]=i+1;
q.push({i,a[i]});
}
while(k--)
{
while(vis[q.top().id])
q.pop();
if(q.top().value<0)//没有坑盈利为正,直接退出·
break;
node temp=q.top();
q.pop();
ans+=temp.value;
int x=temp.id;
vis[l[x]]=vis[r[x]]=1;
a[x]=a[l[x]]+a[r[x]]-a[x];//合并左右两坑
temp.value=a[x];
q.push(temp);
l[x]=l[l[x]],r[x]=r[r[x]];
l[r[x]]=x,r[l[x]]=x;
}
printf("%lld\n",ans);
return 0;
}
来源:CSDN
作者:nefu_cbw
链接:https://blog.csdn.net/weixin_44491423/article/details/104523834