题解:CF436E Cardboard Box
题意:给出 \(n\) 个关卡,你可以花费 \(a_i\) 代价在 \(i\) 关卡获得一颗星,或者花费 \(b_i\) 获得两颗星,求得到 \(k\) 颗星的最小代价,并给出构造。
做法:很明显是反悔贪心。
那么我们考虑每一颗星有几种更新方式。
-
花费 \(a_i\) 代价获得 \(1\) 颗星,代价 \(a_i\)。需要维护零个星中 \(a_i\) 的最小值。
-
花 \(b_i - a_i\) 代价把一个 \(1\) 星升成 \(2\) 星,代价 \(b_i - a_i\)。需要维护一颗星中 \(b_i\) 的最小值。
-
将一个 \(2\) 星变成 \(1\) 星,将一个 \(0\) 星变成 \(2\) 星,代价 \(b_i - (b_j - a_j)\)。需要维护两颗星中 \(b_i - a_i\) 的最大值和 \(0\) 颗星中 \(b_i\) 最小的。
-
将一个 \(1\) 星变成 \(0\) 星,将一个 \(0\) 星变成 \(2\) 星,代价 \(b_i - a_j\),需要维护 \(1\) 颗星中 \(a_i\) 最大的和 \(0\) 颗星中 \(b_i\) 最小的。
用五个堆维护上述操作即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 3e5 + 5;
struct node {
int p, val;
friend bool operator<(node x, node y) {
return x.val > y.val;
}
};
priority_queue<node> p[6]; // a min, (bi - ai) min, b min, ai max, (bi - ai) max
// 选了 0, 选了 1,选了 0,选了 1 个,选了 2 个
int n, m, a[maxn], b[maxn], use[maxn], res;
int solve1() {
while(!p[1].empty() && use[p[1].top().p] != 0)
p[1].pop();
if(p[1].empty())
return 9e18;
return p[1].top().val;
}
int solve2() {
while(!p[2].empty() && use[p[2].top().p] != 1)
p[2].pop();
if(p[2].empty())
return 9e18;
return p[2].top().val;
}
int solve3() {
while(!p[3].empty() && use[p[3].top().p] != 0)
p[3].pop();
while(!p[4].empty() && use[p[4].top().p] != 1)
p[4].pop();
if(p[4].empty() || p[3].empty())
return 9e18;
return p[3].top().val + p[4].top().val;
}
int solve4() {
while(!p[3].empty() && use[p[3].top().p] != 0)
p[3].pop();
while(!p[5].empty() && use[p[5].top().p] != 2)
p[5].pop();
if(p[5].empty() || p[3].empty())
return 9e18;
return p[3].top().val + p[5].top().val;
}
void renew1() {
node x = p[1].top(); p[1].pop();
use[x.p] = 1;
p[2].push(node{x.p, b[x.p] - a[x.p]});
p[4].push(node{x.p, -a[x.p]});
}
void renew2() {
node x = p[2].top(); p[2].pop();
use[x.p] = 2;
p[5].push(node{x.p, a[x.p] - b[x.p]});
}
void renew3() {
node x = p[4].top(), y = p[3].top(); p[4].pop(), p[3].pop();
use[x.p] = 0, use[y.p] = 2;
p[1].push(node{x.p, a[x.p]}), p[3].push(node{x.p, b[x.p]});
p[5].push(node{y.p, a[y.p] - b[y.p]});
}
void renew4() {
node x = p[5].top(), y = p[3].top(); p[5].pop(), p[3].pop();
use[x.p] = 1, use[y.p] = 2;
p[2].push(node{x.p, b[x.p] - a[x.p]}), p[4].push(node{x.p, -a[x.p]});
p[5].push(node{y.p, a[y.p] - b[y.p]});
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i] >> b[i];
for (int i = 1; i <= n; i++)
p[1].push(node{i, a[i]}), p[3].push(node{i, b[i]});
for (int i = 1; i <= m; i++) {
int ans = 9e18, p = 0;
int v[5] = {0, solve1(), solve2(), solve3(), solve4()};
for (int j = 1; j <= 4; j++) {
if(ans > v[j])
ans = v[j], p = j;
}
res += ans;
// cout << i << " " << p << endl;
if(p == 1)
renew1();
if(p == 2)
renew2();
if(p == 3)
renew3();
if(p == 4)
renew4();
}
cout << res << endl;
for (int i = 1; i <= n; i++)
cout << use[i];
cout << endl;
return 0;
}

浙公网安备 33010602011771号