题解 P1484 【种树】

时间:2019-09-12
本文章向大家介绍题解 P1484 【种树】,主要包括题解 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