【洛谷P1484】种树【堆】【贪心】

版权声明:若希望转载,在评论里直接说明即可,谢谢! https://blog.csdn.net/SSL_ZYC/article/details/90729664

题目大意:

题目链接:https://www.luogu.org/problemnew/show/P1484
n n 个点,选择其中互不相邻的不超过 m m 个点,使得点权和最大。


思路:

思维题。
考虑贪心。如果我们第一次选择了最大值点 i i ,那么选择两个点时,要么点 i 1 i-1 和点 i + 1 i+1 一起选,要么两个都不选。

如果我们选择点 i 1 i-1 和点 x ( x i + 1 ) x(x≠i+1) ,那么贪心思想, a [ i 1 ] + a [ x ] a[i-1]+a[x] 必然大于任意 a [ q ] + a [ p ] a[q]+a[p] 。但是当 p = i , q = x p=i,q=x 时, a [ i > 1 ] + a [ x ] a[i-> 1]+a[x] 肯定小于 a [ i ] + a [ x ] a[i]+a[x] (因为一开始 a [ i ] a[i] 是最大的)。矛盾。
证毕

如果不选择 a [ i 1 ] a[i-1] a [ i + 1 ] a[i+1] ,那么就是一个正常的贪心。但是如果选择 a [ i 1 ] a[i-1] a [ i + 1 ] a[i+1] 的话,就需要满足可撤销。
如果我们把 a [ i ] a[i] 的值更改成 a [ i 1 ] + a [ i + 1 ] a [ i ] a[i-1]+a[i+1]-a[i] ,再次选择 a a 数组中最大值,那么 a n s ans 就等于 a [ i ] + a [ i 1 ] + a [ i + 1 ] a [ i ] = a [ i 1 ] + a [ i + 1 ] a[i]+a[i-1]+a[i+1]-a[i]=a[i-1]+a[i+1]

这样用堆维护最大值,就可以做到 O ( m log n ) O(m\log n) 的复杂度


代码:

#include <queue>
#include <cstdio>
#define mp make_pair
using namespace std;
typedef long long ll;

const int N=500010;
int n,m;
bool p[N];
ll a[N],ans;
priority_queue<pair<ll,int> > q;

struct node
{
	int l,r;
}link[N];

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		q.push(mp(a[i],i));
		link[i].l=i-1; link[i].r=i+1;
	}
	while (m--)
	{
		while (p[q.top().second]) q.pop();
		if (q.top().first<0) break;
		ans+=q.top().first;
		int id=q.top().second;
		a[id]=a[link[id].l]+a[link[id].r]-a[id];
		p[link[id].l]=p[link[id].r]=1;
		link[id].l=link[link[id].l].l; link[link[id].l].r=id;
		link[id].r=link[link[id].r].r; link[link[id].r].l=id;
		q.pop(); q.push(mp(a[id],id));
	}
	printf("%lld",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SSL_ZYC/article/details/90729664