题解 P1484 【种树】
Solution 种树
题目大意:给定一个长为\(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;
}
原文地址:https://www.cnblogs.com/colazcy/p/11515147.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法