51nod1380 夹克老爷的逢三抽一

Posted reverymoon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
", ans);
    return 0;
}

 

以上是关于51nod1380 夹克老爷的逢三抽一的主要内容,如果未能解决你的问题,请参考以下文章

51Nod 1380 夹克老爷的逢三抽一

[51nod] 1378 夹克老爷的愤怒 #树形DP

51nod1625 夹克爷发红包(贪心+dfs)

51nod 1378 夹克老爷的愤怒(树型dp+贪心)

51Nod 1378 夹克老爷的愤怒

51Nod1785 数据流中的算法