【题解】 CF436E Cardboard Box 带悔贪心
Legend
\(n\) 个关卡,对每个关卡,你可以花 \(a_i\) 时间得到一颗星,也可以花 \(b_i\) 时间得到两颗星,也可以不玩。问获得 \(w\) 颗星最少需要多少时间。
\(1 \le n \le 3 \times 10^5\),\(1 \le a_i < b_i \le 10^9\),\(1 \le w \le 2n\)。
Link \(\textrm{to Codeforces}\)。
Editorial
这个贪心方法感觉和 [NOI2019]序列 挺像的。
考虑每次只增加一颗星,进行下列操作的哪一个:
- 得到某个关卡的第一颗星,花费 \(a_i\);
- 得到某个关卡的第二颗星,花费 \(b_i-a_i\);
- 直接得到某个关卡的两颗星,并去掉某个关卡的一颗星,花费 \(a_i+(b_i-a_i)-\max(a_j,b_k)\)。
不难发现,上述值都可以使用堆来进行维护。
Code
#include <bits/stdc++.h>
#define debug(...) fprintf(stderr ,__VA_ARGS__)
#define __FILE(x)\
freopen(#x".in" ,"r" ,stdin);\
freopen(#x".out" ,"w" ,stdout)
#define LL long long
const int MX = 3e5 + 23;
using namespace std;
int read(){
char k = getchar(); int x = 0;
while(k < '0' || k > '9') k = getchar();
while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
return x;
}
int vis[MX] ,n ,w;
LL a[MX] ,b[MX];
struct nodeA{bool operator()(int x ,int y){return a[x] < a[y];}};
struct revnodeA{bool operator()(int x ,int y){return a[x] > a[y];}};
struct nodeB{bool operator()(int x ,int y){return b[x] < b[y];}};
struct revnodeB{bool operator()(int x ,int y){return b[x] > b[y];}};
struct nodeAB{bool operator()(int x ,int y){return a[x] + b[x] > a[y] + b[y];}};
priority_queue<int ,vector<int> ,nodeA> A; // 取最大的
priority_queue<int ,vector<int> ,revnodeA> rA; // 取最小的
priority_queue<int ,vector<int> ,nodeB> B;
priority_queue<int ,vector<int> ,revnodeB> rB;
priority_queue<int ,vector<int> ,nodeAB> rAB;
int main(){
n = read() ,w = read();
for(int i = 1 ; i <= n ; ++i){
a[i] = read() ,b[i] = read() - a[i];
rA.push(i) ,rAB.push(i);
}
LL ans = 0;
for(LL i = 1 ,v1 ,v2 ,v3 ; i <= w ; ++i){
while(!A.empty() && (!(vis[A.top()] & 1) || (vis[A.top()] & 2))) A.pop();
while(!rA.empty() && (vis[rA.top()] & 1)) rA.pop();
while(!B.empty() && (vis[B.top()] & 3) != 3) B.pop();
while(!rB.empty() && ((vis[rB.top()] & 2) || !(vis[rB.top()] & 1))) rB.pop();
while(!rAB.empty() && vis[rAB.top()]) rAB.pop();
v1 = v2 = v3 = LLONG_MAX;
if(!rA.empty()) v1 = a[rA.top()];
if(!rB.empty()) v2 = b[rB.top()];
if(!rAB.empty()){
if(!A.empty()) v3 = std::min(v3 ,a[rAB.top()] + b[rAB.top()] - a[A.top()]);
if(!B.empty()) v3 = std::min(v3 ,a[rAB.top()] + b[rAB.top()] - b[B.top()]);
}
LL best = min(min(v1 ,v2) ,v3);
ans += best;
if(v1 == best){
vis[rA.top()] |= 1;
A.push(rA.top());
rB.push(rA.top());
continue;
}
if(v2 == best){
vis[rB.top()] |= 2;
B.push(rB.top());
continue;
}
if(v3 == best){
if(v3 == a[rAB.top()] + b[rAB.top()] - a[A.top()]){
vis[rAB.top()] = 3;
vis[A.top()] &= -1 ^ 1;
rAB.push(A.top());
rA.push(A.top());
}
else{
vis[rAB.top()] = 3;
vis[B.top()] &= -1 ^ 2;
rB.push(B.top());
A.push(B.top());
}
}
}
printf("%lld\n" ,ans);
for(int i = 1 ; i <= n ; ++i)
printf("%d" ,(vis[i] & 1) + ((vis[i] >> 1) & 1));
puts("");
return 0;
}
// very nice greedy problem