题目链接

题目大意:给定一个长为\(n\)的数列,你可以选择不多于\(k\)个数,使得没有两个数相邻,求最大权值和

堆,动态规划


分析:我们很容易就可以想到一个\(O(nk)\)复杂度的\(DP\),但是不太好优化

用类似归纳的思想考虑:

\(k = 1\)时,显然\(ans = max\{a_i\}\)

\(k = 2\)时,我们有两种选择:

  • 选择最大的与\(a_i\)不相邻的\(a_j\)
  • 选择\(a_{i - 1}\)\(a_{i _+ 1}\)

需要证明的是当\(k = 2\)时:\(i - 1\)\(i + 1\)要么同时被选,要么同时落选.

反证法易证:只选其中一个时不是最优解

同时被选:\(a_{i - 1} + a_{i + 1}\)

同时落选:\(a_i + a_j\)

只有一个被选\(a_{i + 1} + a_j\)( \(a_{i - 1}\)同理 )

假设只有一个被选时是最优解:

\(\therefore\)
\(a_{i + 1} + a_j > a_{i - 1} + a_{i + 1}\)

\(a_{i + 1} + a_j > a_i + a_j\)
(和\(a_{i + 1}\)不相邻的\(a_j\)必然不会与\(a_i\)相邻,否则\(j = i - 1\),换言之,两个\(a_j\)是同一个数(因为贪心取最大值) )

\(\therefore\)

\(a_j > a_{i - 1}\)

\(a_{i + 1} > a_{i}\) (不合法,违背了\(k = 1\)时的贪心)

所以我们先找\(k = 1\)时最大的\(a_i\),这对应了两个数都落选的情况,为了避免漏解,我们需要考虑两个数都被选的情况

我们发现:如果选择\(a_{i - 1}\)\(a_{i + 1}\)的话,那么我们的获利就增加了\(a_{i - 1} + a_{i + 1} - a_i\),将其重新放回堆里即可,顺便将\(a_{i - 1}\)\(a_{i + 1}\)打上标记避免重复选择(它们都被选的情况已经由新点表示了)

重复这个过程,我们用一个双向链表来保存每个点左右点,当堆顶为负数时结束即可

#include <cstdio>
#include <cctype>
#include <queue>
using namespace std;
const int maxn = 5e5 + 100;
inline int read(){
	int x = 0,f = 1;char c = getchar();
	while(!isdigit(c))f = c == '-' ? -1 : 1,c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x * f;
}
int l[maxn],r[maxn],vis[maxn],v[maxn],n,k;
long long ans;
struct HeapNode{
	int pos,val;
	bool operator < (const HeapNode &rhs)const{
		return val < rhs.val;
	}
};
priority_queue<HeapNode> Q;
int main(){
	n = read(),k = read();
	for(int i = 1;i <= n;i++)
		Q.push(HeapNode{i,read()}),l[i] = i - 1,r[i] = i + 1;
	l[0] = 1,r[n + 1] = n; 
	while(k--){
		while(vis[Q.top().pos])Q.pop();
		HeapNode h = Q.top();Q.pop();
		if(h.val < 0)break;
		ans += h.val;
		int now = h.pos;
		v[now] = v[l[now]] + v[r[now]] - v[now];
		h.val = v[now];
		vis[l[now]] = vis[r[now]] = 1;
		l[now] = l[l[now]];r[l[now]] = now;
		r[now] = r[r[now]];l[r[now]] = now;
		Q.push(h);
	}
	return printf("%lld\n",ans),0;
}

相关文章:

  • 2021-06-27
  • 2022-01-24
  • 2021-10-26
  • 2021-09-07
  • 2022-12-23
  • 2021-12-21
  • 2021-10-27
  • 2022-02-28
猜你喜欢
  • 2022-01-19
  • 2021-12-25
  • 2022-02-08
  • 2022-12-23
相关资源
相似解决方案