bzoj 2151: 种树

2151: 种树

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 524  Solved: 281
[Submit][Status][Discuss]

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

HINT

 

Source

 

 

堆贪心。

每次选择美观度最大的点x, 将x左边的点L和x右边的点R删去。

但是这样贪心可能无法保证正确性, 需要将操作实现可撤销。

每次选择美观度最大的点x后, 将x左边的点L和x右边的点R删去, 将x再次push进堆, 并使a[x] = a[L] + a[R] - a[x];

具体实现可使用双向链表维护L,R

 

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;

inline void read(int &x) 
{
    static int f;
    static char c;
    for (f = 1; !isdigit(c = getchar()); ) if (c == '-') f = -1;
    for (x = 0; isdigit(c); c = getchar()) x = x * 10 + c - 48;
    x *= f;
}

struct data {
    int v, p;
    bool operator < (const data &X) const {
        return v < X.v;
    }
};

priority_queue<data> Q;

int ans;
int N, M;
int a[MAXN];
int pre[MAXN];
int nxt[MAXN];
bool del[MAXN];

void Insert()
{
    while (del[Q.top().p]) Q.pop();
    data X = Q.top(); Q.pop();
    int P = X.p;

    ans += a[P];
    a[P] = a[pre[P]] + a[nxt[P]] - a[P];
    Q.push((data) {a[P], P});

    nxt[pre[pre[P]]] = P;
    pre[nxt[nxt[P]]] = P;
    del[nxt[P]] = del[pre[P]] = 1;
    pre[P] = pre[pre[P]];
    nxt[P] = nxt[nxt[P]];

}

int main()
{
    read(N), read(M);
    if (N < M * 2) {
        puts("Error!");
        return 0;
    }
    for (int i = 1; i <= N; ++ i) {
        read(a[i]);
        Q.push((data) {a[i], i});
        pre[i] = i - 1;
        nxt[i] = i + 1;
    }
    pre[1] = N;
    nxt[N] = 1;

    while (M --) {
        Insert();
    }
    printf("%d", ans);
    return 0;
}
View Code

 

__Stay hungry, Stay foolish.
posted @ 2016-05-19 14:06  jszyxw  阅读(164)  评论(0编辑  收藏  举报