zoukankan      html  css  js  c++  java
  • 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;
        }
    
  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9288761.html
Copyright © 2011-2022 走看看