Loading

「题解」[BZOJ 3728] Final Zarowki

提供一种不用堆的做法.

考虑贪心, 对于一个房间, 选择不小于它所需功率且功率最小的灯泡一定是最优的, 因为这样子能够最大程度的利用灯泡, 同时对 \({w_i}\) 从大到小排序, 这样可以使功率大的灯泡浪费的更少.

对每一个房间寻找不小于它所需功率且功率最小的灯泡, 将答案加上灯泡功率, 然后删去这个灯泡. 如果找不到, 则代表需要换一次灯泡, 并记录下换灯泡的次数 \(t\).

最后对每个房间过剩的功率 (即这个房间灯泡的功率减去这个房间的所需功率) 进行从大到小排序, 将答案减去前 \(k-t\) 个值, 即可得到答案.

特别地, 如果 \(t\) 大于 \(k\), 则表示这是一种无解状态, 输出 NIE

因此我们需要维护一组数据, 要进行以下操作:

  • 插入一个数 \(x\)
  • 删除一个数 \(x\)
  • 寻找不小于数 \(x\) 且最小的数

发现以上操作可以用平衡树解决, 由于此题空间较紧, 同时考虑代码难度等多方面因素, 可以使用 \(\texttt{STL::set}\) 代替平衡树完成以上操作.

时间复杂度 \(\Theta(n \log n)\).

#define ll long long
#define it std::multiset<int>::iterator

using std::multiset;

const int N = 5e5;

int n, flag, tot, p[N + 10], w[N + 10], qaq[N + 10];
ll ans;

multiset<int> s;

bool cmp(int x, int y) { return x > y; }

signed main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) cin >> p[i], s.insert(p[i]);
    for (int i = 1; i <= n; i++) cin >> w[i];
    std::sort(w + 1, w + 1 + n);
    for (int i = n; i; i--) {
        int x = w[i];
        it tmp = s.upper_bound(x - 1);
        if (tmp == s.end())
            ans += x, flag++;
        else
            ans += *tmp, qaq[++tot] = *tmp - x, s.erase(tmp++);
    }
    if (flag > k) return cout << "NIE" << endl, 0;
    std::sort(qaq + 1, qaq + 1 + tot, cmp);
    for (int i = 1; i <= k - flag; i++) ans -= qaq[i];
    return cout << ans << endl, 0;
}
posted @ 2021-06-01 10:25  Aestas16  阅读(35)  评论(0编辑  收藏  举报