CF436E Cardboard Box
题意:有两个数组a和b,你可以花费\(a_i\)代价买1个球,也可以花费\(b_i\)代价买两个,也可以不买,每个i只能有一个操作。问买到恰好k个球的最小代价。
我目前见过的最复杂的反悔贪心。
我们贪心的想每次一个一个球的加,那么我们有四种加法:
- 从没有用过的i里用\(a_i\)代价买一个球。
- 从用\(a_i\)的i里选择用\(b_i\)买两个球,之前买的那个球退还,代价是 \(b_i\) - \(a_i\)。
- 从没有用过的i里选\(b_i\)买两个球,然后从之前用\(a_j\)的j里退还一个球,代价是 \(b_i\) - \(a_j\)。
- 从没有用过的i里选\(b_i\)买两个球,然后之前用\(b_j\)的j里退还一个球,变成用\(a_j\)买一个球,代价是 \(b_i\) - (\(b_j\) - \(a_j\))
那么我们用set维护最小的没买过球位置的\(a_i\), 最小的买一个球位置的\(b_i\) - \(a_i\),最大的买过一个球位置的\(a_i\),最大的买过两个球位置的\(b_i\) - \(a_i\), 最小的没买过球位置的\(b_i\)。 那么第一二个操作好说,第三个操作就是最小的没买过球位置的\(b_i\) - 最大的买过一个球位置的\(a_i\), 第四个操作就是最小的没买过球位置的\(b_i\) - 最大的买过两个球位置的\(b_i\) - \(a_i\)。
注意每次操作对四个set的影响。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<i64> a(n), b(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i] >> b[i];
}
using PII = std::pair<i64, int>;
std::set<PII, std::greater<PII> > s3, s4;
std::set<PII> s1, s2, s5;
for (int i = 0; i < n; ++ i) {
s1.insert({a[i], i});
s5.insert({b[i], i});
}
std::string ans(n, '0');
i64 sum = 0;
while (k -- ) {
i64 min = 1e18, op = 0;
if (s1.size() && s1.begin()->first < min) {
min = s1.begin()->first;
op = 1;
}
if (s2.size() && s2.begin()->first < min) {
min = s2.begin()->first;
op = 2;
}
if (s5.size() && s3.size() && s5.begin()->first - s3.begin()->first < min) {
min = s5.begin()->first - s3.begin()->first;
op = 3;
}
if (s5.size() && s4.size() && s5.begin()->first - s4.begin()->first < min) {
min = s5.begin()->first - s4.begin()->first;
op = 4;
}
sum += min;
if (op == 1) {
int i = s1.begin()->second;
s1.erase({a[i], i});
s2.insert({b[i] - a[i], i});
s3.insert({a[i], i});
s4.erase({b[i] - a[i], i});
s5.erase({b[i], i});
ans[i] = '1';
} else if (op == 2) {
int i = s2.begin()->second;
s1.erase({a[i], i});
s2.erase({b[i] - a[i], i});
s3.erase({a[i], i});
s4.insert({b[i] - a[i], i});
s5.erase({b[i], i});
ans[i] = '2';
} else if (op == 3) {
int i = s5.begin()->second, j = s3.begin()->second;
s1.erase({a[i], i});
s2.erase({b[i] - a[i], i});
s3.erase({a[i], i});
s4.insert({b[i] - a[i], i});
s5.erase({b[i], i});
s1.insert({a[j], j});
s2.erase({b[j] - a[j], j});
s3.erase({a[j], j});
s4.erase({b[j] - a[j], j});
s5.insert({b[j], j});
ans[i] = '2';
ans[j] = '0';
} else if (op == 4) {
int i = s5.begin()->second, j = s4.begin()->second;
s1.erase({a[i], i});
s2.erase({b[i] - a[i], i});
s3.erase({a[i], i});
s4.insert({b[i] - a[i], i});
s5.erase({b[i], i});
s1.erase({a[j], j});
s2.insert({b[j] - a[j], j});
s3.insert({a[j], j});
s4.erase({b[j] - a[j], j});
s5.erase({b[j], j});
ans[i] = '2';
ans[j] = '1';
}
}
std::cout << sum << "\n";
std::cout << ans << "\n";
}

浙公网安备 33010602011771号