「题解」[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;
}