51nod1380 夹克老爷的逢三抽一

问题等价于选出$n / 3$个不相邻元素是权值和最大

这是一个经典贪心问题,同种树,拿堆维护即可,复杂度$O(n \log n)$

#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;

extern inline char gc() {
    static char RR[23456], *S = RR + 23333, *T = RR + 23333;
    if(S == T) fread(RR, 1, 23333, stdin), S = RR;
    return *S ++;
}
inline int read() {
    int p = 0, w = 1; char c = gc();
    while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
    while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
    return p * w;
}

#define ll long long
#define ri register int
#define sid 200050

int n, k;
bool gg[sid];
ll ans, v[sid], pre[sid], nxt[sid];

struct Man {
    ll id, val;
    Man() {}
    Man(ll _i, ll _v) : id(_i), val(_v) {}
    friend bool operator < (Man a, Man b)
    { return a.val < b.val; }
} ;
priority_queue <Man> q;

inline void del(int o) {
    pre[nxt[o]] = pre[o];
    nxt[pre[o]] = nxt[o];
    gg[o] = 1;
}

int main() {
    n = read();
    for(ri i = 1; i <= n; i ++) v[i] = read();
    
    for(ri i = 1; i <= n; i ++) {
        pre[i] = i - 1; nxt[i] = i + 1;
        q.push(Man(i, v[i]));
    }
    pre[1] = n; nxt[n] = 1;

    k = n / 3;
    for(ri i = 1; i <= k; i ++) {
        Man o; int id;
        while(1) {
            o = q.top(); q.pop();
            id = o.id; if(!gg[id]) break;
        }
        ans += v[id];
        v[id] = v[pre[id]] + v[nxt[id]] - v[id];
        q.push(Man(id, v[id]));
        del(pre[id]); del(nxt[id]);
    }
    printf("%lld\n", ans);
    return 0;
}

 

posted @ 2018-08-30 07:59  remoon  阅读(226)  评论(0编辑  收藏  举报