题目大意: 有 n n n 轮游戏,第 i i i 轮游戏拿 1 1 1 颗星的代价为 a i a_i ai,拿 2 2 2 颗星的代价为 b i b_i bi,不拿代价为 0 0 0,问拿到恰好 w w w 颗星的最小代价。
题解
考虑带反悔策略的贪心。
增加一颗星时,有四种情况:
- 把一个 0 0 0 星变成 1 1 1 星,代价增加 a i a_i ai。
- 把一个 1 1 1 星变成 2 2 2 星,代价增加 b i − a i b_i-a_i bi−ai。
- 把一个 1 1 1 星变成 0 0 0 星,把另一个 0 0 0 星变成 2 2 2 星,代价为 b j − a i b_j-a_i bj−ai。
- 把一个 2 2 2 星变成 1 1 1 星,把另一个 0 0 0 星变成 2 2 2 星,代价为 b j − ( b i − a i ) b_j-(b_i-a_i) bj−(bi−ai)。
于是用小根堆维护 a i , b i − a i , b j , − a i , − ( b i − a i ) a_i~,~b_i-a_i~,~b_j~,~-a_i~,~-(b_i-a_i) ai , bi−ai , bj , −ai , −(bi−ai),每次取四种中最优即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn 300010
#define ll long long
#define inf 100000000000000ll
int n,k,a[maxn],b[maxn];
struct par{
ll val;int pos;};
struct cmp{
bool operator ()(const par A,const par B)const
{
return A.val>B.val;}
};
priority_queue< par,vector<par>,cmp > q1,q2,q3,q4,q5;
int ans[maxn];ll tot=0;
void add0(int x){
ans[x]=0;
q1.push((par){
a[x],x});
q3.push((par){
b[x],x});
}
void add1(int x){
ans[x]=1;
q2.push((par){
b[x]-a[x],x});
q4.push((par){
-a[x],x});
}
void add2(int x){
ans[x]=2;
q5.push((par){
a[x]-b[x],x});
}
int main()
{
scanf("%d %d",&n,&k);
q1.push((par){
inf,0});
q2.push((par){
inf,0});
q3.push((par){
inf,0});
q4.push((par){
inf,0});
q5.push((par){
inf,0});
for(int i=1;i<=n;i++){
scanf("%d %d",&a[i],&b[i]);
add0(i);
}
while(k--){
int p1=q1.top().pos,p2=q2.top().pos,p3=q3.top().pos,p4=q4.top().pos,p5=q5.top().pos;
while(q1.size()>1&&ans[p1]!=0)q1.pop(),p1=q1.top().pos;
while(q2.size()>1&&ans[p2]!=1)q2.pop(),p2=q2.top().pos;
while(q3.size()>1&&ans[p3]!=0)q3.pop(),p3=q3.top().pos;
while(q4.size()>1&&ans[p4]!=1)q4.pop(),p4=q4.top().pos;
while(q5.size()>1&&ans[p5]!=2)q5.pop(),p5=q5.top().pos;
ll t1=q1.top().val;
ll t2=q2.top().val;
ll t3=q3.top().val+q4.top().val;
ll t4=q3.top().val+q5.top().val;
ll mi=min(min(t1,t2),min(t3,t4));tot+=mi;
if(t1==mi){
q1.pop();
add1(p1);
}else if(t2==mi){
q2.pop();
add2(p2);
}else if(t3==mi){
q3.pop();q4.pop();
add2(p3);add0(p4);
}else{
q3.pop();q5.pop();
add2(p3);add1(p5);
}
}
printf("%lld\n",tot);
for(int i=1;i<=n;i++)printf("%d",ans[i]);
}