2019牛客多校第七场 C.Governing sand(贪心)

很多棵树,砍掉一些树使得最高的树的个数是总数的两倍,问砍树的最小花费。

wa了很多发,写篇博客纪念一下(并不值得纪念)。

每棵树都有成为最高的树的潜力,只要你把比它高的都砍掉。
那么把树按高度排序,首先计算把比它高的树都砍掉的花费以及砍了多少树,这部分用两个前缀和O(1)求出。
如果砍完比它高的树就已经满足条件了,那么更新答案,如果还不行,就还要砍掉一些比它矮的,这时候贪心的砍花费小的,由于花费最大只有200,整个桶(计数数组)暴力维护一下,如果花费特别大,就需要离散化+线段树了(事实上我都写完了线段树了正准备离散化,回去一看数据范围立马窒息,由于题解里也是线段树高度怀疑出题人把c和p搞反了)。

wa了很多发,一开始是没注意到原来相同高度但是砍掉代价不同的会分开输入,然后就是各种写挫,愣是不忍心删代码于是写篇博客存着。

ac代码:

#include

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 5;

int n;

struct trees {
    ll h, c, p;
} ts[maxn];

bool cmp(trees &a, trees &b) {
    return a.h < b.h;
}

//价值前缀和,个数前缀和
ll sum[maxn], sum2[maxn];

ll cost[205];

void solve() {
    memset(cost, 0, sizeof(cost));
    ll cut = 0, val = 0;
    const ll all = sum2[n];
    ll ans = INT64_MAX;
    for (int i = 1; i <= n; ++i) {
        int st = i;
        ll sump = ts[i].p;
        while (ts[i + 1].h == ts[i].h) {
            sump += ts[++i].p;
        }
        cut = sum2[n] - sum2[i];
        val = sum[n] - sum[i];
        if (sump > (all - cut) / 2) {
            ans = min(ans, val);
        } else {
            ll tot = 0;
            for (int j = 1; j <= 200; ++j) {
                if (!cost[j]) {
                    continue;
                }
                if (sump <= (all - (cut + cost[j])) / 2) {
                    tot += cost[j] * j;
                    cut += cost[j];
                } else {
                    tot += (all - 2 * sump - cut + 1) * j;
                    break;
                }
            }
            ans = min(ans, val + tot);
        }
        for (int j = st; j <= i; ++j) {
            cost[ts[j].c] += ts[j].p;
        }
    }
    printf("%lld\n", ans);
}

int main() {
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; ++i) {
            scanf("%lld%lld%lld", &ts[i].h, &ts[i].c, &ts[i].p);
        }
        ts[n + 1] = {-1, -1, -1};
        sort(ts + 1, ts + n + 1, cmp);
        for (int i = 1; i <= n; ++i) {
            sum[i] = sum[i - 1] + ts[i].c * ts[i].p;
            sum2[i] = sum2[i - 1] + ts[i].p;
        }
        solve();
    }
    return 0;
}
/*
5
1 9 2
2 7 6
3 1 1
4 3 1
5 100 1

4
1 9 6
1 4 7
1 6 1
1 8 8


6
2 4 2
2 3 2
3 2 2
3 1 2
4 5 2
4 6 2
 */

你可能感兴趣的:(ACM,贪心)