• BZOJ_2151_种树_贪心+堆+链表


    BZOJ_2151_种树_贪心+堆

    Description

    A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。

    Input

    输入的第一行包含两个正整数n、m。第二行n个整数Ai。

    Output

    输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。

    Sample Input

    【样例输入1】
    7 3
    1 2 3 4 5 6 7
    【样例输入2】
    7 4
    1 2 3 4 5 6 7

    Sample Output

    【样例输出1】
    15

    【样例输出2】
    Error!
    【数据规模】
    对于全部数据:m<=n;
    -1000<=Ai<=1000
    N的大小对于不同数据有所不同:
    数据编号 N的大小 数据编号 N的大小
    1 30 11 200
    2 35 12 2007
    3 40 13 2008
    4 45 14 2009
    5 50 15 2010
    6 55 16 2011
    7 60 17 2012
    8 65 18 199999
    9 200 19 199999
    10 200 20 200000


    首先有$O(n^2)$的暴力显然,于是你这道题就可以拿到70分..

    我们考虑贪心,每次挑最大的那个删除,同时把左右的也删除,这显然是错的,因为可能有3 5 4,我选3+4要比选5更优。

    但是5仍然非常重要,因为你需要同时选2个才可以不选这个5。

    于是有了另外一种可以反悔的贪心的思路:每次找最大的并把它两边删除,把这个数修改成它的权值减去两边的权值,其中找最大的用一个堆来维护,找两边的数用链表。

    这样就是对的了,因为这相当于我每次都会取出一个数,并且保证每次对答案的贡献增加的最多。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define N 200050
    int n,m,a[N],kill[N];
    struct node {
        int v,p;
        node() {}
        node(int v_,int p_) :
            v(v_),p(p_) {}
        inline bool operator < (const node &x) const {
            return v<x.v;
        }
    };
    priority_queue<node>q;
    int L[N],R[N];
    void del(int x) {
        L[R[x]]=L[x];
        R[L[x]]=R[x];
    }
    int main() {
        // freopen("tree.in","r",stdin);
        // freopen("tree.out","w",stdout);
        scanf("%d%d",&n,&m);
        if(m>n/2) {
            puts("Error!"); return 0;
        }
        int i;
        for(i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            q.push(node(a[i],i)); L[i]=i-1; R[i]=i+1;
        }
        R[n]=1; L[1]=n; int ans=0;
        for(i=1;i<=m;i++) {
            while(!q.empty()&&kill[q.top().p]) q.pop();
            node t=q.top(); q.pop();
            kill[L[t.p]]=kill[R[t.p]]=1;
            a[t.p]=a[L[t.p]]+a[R[t.p]]-a[t.p];
            del(L[t.p]); del(R[t.p]);
            ans+=t.v;
            q.push(node(a[t.p],t.p));
        }
        printf("%d
    ",ans);
    }
    
  • 相关阅读:
    String判空效率比较
    myeclipse数据库逆向hibernate教程
    博客使用说明和我的学习心得(技术路线和书单)
    【小记】go如何判断key是否在map中
    MySQL必知必会笔记——MySQL其他操作
    MySQL必知必会笔记——查询的进阶知识
    MySQL必知必会笔记——查询的基础知识
    MySQL必知必会笔记-Mysql基本操作
    Linux学习笔记:Linux命令之权限管理命令
    Linux学习笔记:用户与用户组
  • 原文地址:https://www.cnblogs.com/suika/p/9062716.html
Copyright © 2020-2023  润新知