SGU 148 枚举

题意

传送门 SGU 148 B-Station

题解

自顶而下枚举层 i i i,计算摧毁 i → n i\rightarrow n in 需要的最小花费。暴力计算 O ( n 2 ) O(n^2) O(n2)

s u m [ i + 1 ] sum[i+1] sum[i+1] 代表 0 ⋯ i 0\cdots i 0i 关于 L L L 的前缀和。那么枚举 i i i 时,实际上需要花钱摧毁的位置 j j j 满足 s u m [ j + 1 ] − s u m [ i ] ≤ L [ i ] sum[j+1]-sum[i]\leq L[i] sum[j+1]sum[i]L[i]。前缀和单调不降,那么需要花钱摧毁的集合满足单调性。 O ( n ) O(n) O(n) 求解即可。

#include <bits/stdc++.h>
using namespace std;
constexpr int MAXN = 15E3 + 5;
int N, W[MAXN], L[MAXN], P[MAXN];
int sum[MAXN], F[MAXN], idx[MAXN];

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> N;
    for (int i = 0; i < N; ++i)
        cin >> W[i] >> L[i] >> P[i];
    for (int i = 0; i < N; ++i)
        sum[i + 1] = sum[i] + W[i];
    for (int i = 0; i < N; ++i)
        F[i] = sum[i + 1] - L[i];
    iota(idx, idx + N, 0);
    sort(idx, idx + N, [&](const int i, const int j)
         { return F[i] < F[j]; });
    int cost = 1e9, id = -1;
    set<int> st;
    for (int i = 0, j = 0, s = 0; i < N; ++i)
    {
        while (j < N && F[idx[j]] <= sum[i])
        {
            if (idx[j] >= i)
                s += P[idx[j]], st.insert(idx[j]);
            ++j;
        }
        if (s < cost)
            cost = s, id = i;
        int k;
        while (st.size() && (k = *st.begin()) <= i)
            s -= P[k], st.erase(k);
    }
    for (int i = id; i < N; ++i)
        if (F[i] <= sum[id])
            cout << i + 1 << '\n';
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值