LG1484 种树

题意

(N)个数,至多选(k)个,相邻两数不能同时选,问最大价值。

思路

一种假的思路:直接扔进对里面,每次都选最大的可以选的,再把两边和自己标记为不能选,一直贪心下去。是不是很有道理?
假在哪里?虽然这个是最大的,旁边两个加起来比它大,就错了。
把这个假贪心改一改,赐予它一个反悔的机会。如果它不选(i),那么它可以选则(last[i])(next[i]),这两个一定是一起选的(因为在一起才有超过(i)的可能)。此时它的价值为(a[last[i]]+a[next[i]]),原先已经选了(a[i]),所以就再扔一个(a[last[i]]+a[next[i]]-a[i]) 进去取代原来的数。由于这样选了(2)个数,而选一次反悔一次也恰好用掉(2)次机会,所以正好。
置于维护(last、next)只要用双向链表就好了

#include <bits/stdc++.h>
using namespace std;
pair<int,int> t;
const int N=500005;
int n,k,a[N],f[N],last[N],Next[N];
long long ans;
priority_queue <pair<int,int>> q;
int main(){
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		q.push(make_pair(a[i],i));
	}
	for (int i=1;i<=n;i++) last[i]=i-1,Next[i]=i+1;
	last[n+1]=n,Next[0]=1;
	for (int i=1;i<=k;i++){
		t=q.top();
		while (f[t.second]) q.pop(),t=q.top();
		q.pop();
		if (t.first<0) break;
		ans+=t.first;
		int id=t.second;
		f[last[id]]=f[Next[id]]=1;
		a[id]=a[last[id]]+a[Next[id]]-a[id];
		q.push(make_pair(a[id],id));
		last[id]=last[last[id]],Next[id]=Next[Next[id]];
		Next[last[id]]=id,last[Next[id]]=id;
	}
	printf("%lld",ans);
}
* 生而自由 爱而无畏 *
原文地址:https://www.cnblogs.com/flyfeather6/p/10632781.html