题解:CF436E Cardboard Box
做一道 IOI 的题时需要用这个,以前没写这个,现在补一下,还是很典的,加深了对反悔贪心的理解。
CF436E
首先很明显,如果要用反悔贪心做这题,大体思路就是看每选一个星星最少可以用多少时间。但是注意到如果你的决策只有 \(0 \to 1\) 和 \(1 \to 2\) 的话,肯定是不对的,可能会有拿第一颗星花很久,但是第二颗极快的情况。于是我们要在这个决策集里再加上所有可以反悔,并且使总星数加 \(1\) 的决策。所以总的决策集就是:
- 选一个下标 \(0 \to 1\),需要维护 \(a_i\) 的最小值。
- 选一个下标 \(1 \to 2\),需要维护 \(b_i - a_i\) 的最小值。
- 选一个下标 \(1 \to 0\),另一个下标 \(0 \to 2\),需要维护 \(-a_i\),\(b_i\) 的最小值。
- 选一个下标 \(2 \to 1\),另一个下标 \(0 \to 2\),需要维护 \(a_i - b_i\),\(b_i\) 的最小值。
这是所有的反悔情况。显然需要维护五个堆,实现方面我参考了一位大佬的“可删堆”,其本质就是将那个弹出无效的元素放在所有普通堆操作的前面,然后封装起来。有了这样的封装,也无需再手动弹出了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+7;
int n,w,a[N][3],st[N];
struct Misaka{
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;
int id;
void re(){while(q.size()&&st[q.top().second]!=id)q.pop();}
int size(){re();return q.size();}
void push(pair<int,int> x){q.push(x);}
pair<int,int> top(){re();return q.top();}
} q[6];
void to0(int x){st[x]=0;q[1].push({a[x][1]-a[x][0],x});q[2].push({a[x][2]-a[x][0],x});}
void to1(int x){st[x]=1;q[3].push({a[x][0]-a[x][1],x});q[4].push({a[x][2]-a[x][1],x});}
void to2(int x){st[x]=2;q[5].push({a[x][1]-a[x][2],x});}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>w;
for(int i=1;i<=n;i++) cin>>a[i][1]>>a[i][2];
q[1].id=q[2].id=0,q[3].id=q[4].id=1,q[5].id=2;
for(int i=1;i<=n;i++) q[1].push({a[i][1],i}),q[2].push({a[i][2],i});
int ans=0;
while(w--){
int op=-1,mn=1e18;
if(q[1].size()) if(mn>q[1].top().first) mn=q[1].top().first,op=1;
if(q[4].size()) if(mn>q[4].top().first) mn=q[4].top().first,op=2;
if(q[3].size()&&q[2].size()) if(mn>q[3].top().first+q[2].top().first) mn=q[3].top().first+q[2].top().first,op=3;
if(q[5].size()&&q[2].size()) if(mn>q[5].top().first+q[2].top().first) mn=q[5].top().first+q[2].top().first,op=4;
ans+=mn;
if(op==1) to1(q[1].top().second);
else if(op==2) to2(q[4].top().second);
else if(op==3) to0(q[3].top().second),to2(q[2].top().second);
else to1(q[5].top().second),to2(q[2].top().second);
}
cout<<ans<<"\n";
for(int i=1;i<=n;i++) cout<<st[i];
cout<<"\n";
return 0;
}
本文来自博客园,作者:GE9x,转载请注明原文链接:https://www.cnblogs.com/GE9X/p/19664118

浙公网安备 33010602011771号