• P1484 种树


    P1484 种树

    题目描述
    cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

    输入输出格式
    输入格式:
    第一行,两个正整数n,k。

    第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。

    输出格式:
    输出1个数,表示cyrcyr种树的最大获利。


    第一种思路DP:(dp[i][j]) 代表前(i)个格子种(j)棵树的最大获利,有dp方程 (dp[i][j] = max(dp[i - 1][j],dp[i - 2][j - 1]))

    然而数据范围不允许这(O(n ^ {2}))的算法

    用数学归纳法可以证明:对于一个位置,我们要么取当前,要么不取当前取两旁,最后答案最大

    我们创建一个大根堆,每次取最大值加入答案中,标记一下左右两边不可取,再把 (a[i -1] + a[i + 1] - a[i])丢入堆中

    值得注意的是,为了除去第一个值和最后一个值对答案的影响(虽然在本题没有体现),我们给第0个和最后一个赋一个极小值

    为什么呢?这里我们提供了一个反悔选项,若是下次选最大值选到了(a[i -1] + a[i + 1] - a[i]),观察这两次的结果:前一次:(ans + a[i]),后一次:(ans + a[i] + a[i - 1] + a[i +1] - a[i] = a[i - 1] + a[i + 1]),这不就是反悔,选择两旁而不选中间了吗

    复杂度 (O(klog N))

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<climits>
    typedef long long LL;
    using namespace std;
    LL RD(){
        LL out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int maxn = 5000019;
    struct Node{
        LL val,index;
        Node (int val, int index):val(val), index(index){}
        Node(){}
        bool operator < (const Node &a)const{return val < a.val;}
        }I[maxn];
    priority_queue<Node>Q;
    LL num,k;
    LL a[maxn];
    bool used[maxn];
    LL ans;
    int l[maxn],r[maxn];
    int main(){
        num = RD();k = RD();
        for(int i = 1;i <= num;i++){
            l[i] = i - 1,r[i] = i + 1;
            a[i] = RD();
            Q.push(Node(a[i],i));
            }
        while(k--){
            while(used[Q.top().index])Q.pop();
            Node now = Q.top();Q.pop();
            if(now.val < 0)break;
            ans += now.val;
            int p = now.index;
            a[p] = a[l[p]] + a[r[p]] - a[p];
            Q.push(Node(a[p],p));
            used[l[p]] = used[r[p]] = 1;
            l[p] = l[l[p]],r[p] = r[r[p]];
            r[l[p]] = p,l[r[p]] = p;
            }
        printf("%lld
    ",ans);
        return 0;
        }
    
  • 相关阅读:
    HDU
    android 博客园
    android105 jni概念
    android104 帧动画,补间动画,属性动画
    requestFocusFromTouch , requestFocus
    android103 内容观察者
    android102 查询,插入联系人
    android101 获取、备份、插入短信
    android100 自定义内容提供者
    android99 拍照摄像
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9288761.html
Copyright © 2020-2023  润新知