2018.11.1模拟赛总结
Posted alessandro
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018.11.1模拟赛总结相关的知识,希望对你有一定的参考价值。
贪心 + 堆
因为可以不选满,所以可以把小于 (0) 的值赋值为 (0), 先考虑按 (a_i) 从大到小排序, 然后考虑选择 ([A + 1 dots n]) 中最大的 (b_i).但是这样不一定会成为最优解,我们从 (A + 1) 开始向 (A + B) 扫描,每一次尝试放弃前面的一个 (a_i) , 然后用当前的物品更新 (a_i) 的答案。前者可以通过用一个包含了第 (A) 个物品的 (b_i - a_i) 的 (set) 维护,后者可以通过最大堆维护。
每次更新答案的过程中需要把当前物品的 (b_i - a_i) 插到 (set) 中去,因为可以返回,所以在这之后可能被取出
时间复杂度 (nlogn)
#include <set>
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 10;
typedef pair<int, int> P;
#define A first
#define val first
#define B second
P a[maxn];
int n, la, lb;
int now, ans;
set<P> s1;
priority_queue<P> s2;
int main() {
scanf("%d%d%d", &n, &la, &lb);
for (int i = 1; i <= n; ++ i)
scanf("%d", &a[i].A), a[i].A = max(a[i].A, 0);
for (int i = 1; i <= n; ++ i)
scanf("%d", &a[i].B), a[i].B = max(a[i].B, 0);
sort(a + 1, a + n + 1); reverse(a + 1, a + n + 1);
for (int i = n; i > la; -- i) {
now += a[i].B;
s1.insert(P(a[i].B, i));
if (s1.size() > lb) {
now -= s1.begin() -> val;
s1.erase(s1.begin());
}
}
for (int i = 1; i <= la; ++ i) {
s2.push(P(a[i].B - a[i].A, i));
now += a[i].A;
}
ans = now;
for (int i = la + 1; i <= la + lb; ++ i) {
set<P>::iterator it = s1.find(P(a[i].B, i));
if (it != s1.end()) {
now -= it -> val;
s1.erase(it);
} else {
it = s1.begin();
now -= it -> val;
s1.erase(it);
}
s2.push(P(a[i].B - a[i].A, i));
now += a[i].A;
now += s2.top().val; s2.pop();
ans = max(ans, now);
}
cout << ans << endl;
}
以上是关于2018.11.1模拟赛总结的主要内容,如果未能解决你的问题,请参考以下文章