2018.11.1模擬賽總結
阿新 • • 發佈:2018-11-01
維護 top 過程 ever 選擇 cpp const a + b space 中去,因為可以返回,所以在這之後可能被取出
貪心 + 堆
因為可以不選滿,所以可以把小於 \(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模擬賽總結