CF436E Cardboard Box 题解

Problem

CF436E Cardboard Box

\(n\) 个关卡,对每个关卡,你可以花 \(a_i\) 代价得到一颗星,也可以花 \(b_i\) 代价得到两颗星,也可以不玩。问获得 \(w\) 颗星最少需要多少时间。

Sol

反悔贪心好题。

时隔半年终于落实了

我们考虑如何如何多拿一颗星星:

  1. 0 -> 1(在一个不拿星星的关卡里拿一颗星星)

  2. 1 -> 2

发现需要反悔才可以。

于是

  1. 2 -> 1 ,0 -> 2

  2. 1 -> 0 , 0 -> 2

开 5 个堆记录就行了,细节见代码注释。

Code

#define in read()
#define fi first
#define se second
#define pair<int,int> pii

typedef long long ll;

int read(){
	int x = 0,sgn = 1;char ch = getchar();
	for(;!isdigit(ch);ch = getchar()) if(ch == '-') sgn = -1;
	for(;isdigit(ch);ch = getchar()) x = (x<<1)+(x<<3)+(ch^48);
	return x*sgn;
}

priority_queue<pii,vector<pii>,greater<pii> > q[5];
//小根堆
const int N = 3e5+10;
const int inf = 0x7fffffff;

int vis[N],a[N],b[N],statu[5] = {0,1,2,1,0};
ll t[5],th[5]; //血泪的教训,一定要开 long long
int n,m;
ll ans;
/*	
	q[0] : 0 -> 1
	q[1] : 1 -> 2
	q[2] : 2 -> 1
	q[3] : 1 -> 0
	q[4] : 0 -> 2
*/
void add0(int x){
	q[0].push(pii(a[x],x));
	q[4].push(pii(b[x],x));
	vis[x] = 0;
}

void add1(int x){
	q[1].push(pii(b[x]-a[x],x));
	q[3].push(pii(-a[x],x));
	vis[x] = 1;
}

void add2(int x){
	q[2].push(pii(a[x]-b[x],x));
	vis[x] = 2;
}

int main (){
	n = in,m = in;
	for(int i = 0;i < 5;i++) q[i].push(pii(inf,0));
	for(int i = 1;i <= n;i++) a[i] = in,b[i] = in,add0(i);
	for(int i = 1;i <= m;i++){
		for(int j = 0;j < 5;j++) {
			t[j] = q[j].top().fi,th[j] = q[j].top().se;
			while(t[j] < inf && th[j] && statu[j] != vis[th[j]]){
				q[j].pop(); t[j] = q[j].top().fi,th[j] = q[j].top().se;
			}
		}
		ll minn = inf;
		minn = min(t[0],min(t[1],min(t[2]+t[4],t[3]+t[4])));
		if(minn == t[0]){
			q[0].pop(); add1(th[0]);
		}else if(minn == t[1]){
			q[1].pop(); add2(th[1]);
		}else if(minn == t[2] + t[4]){
			q[2].pop(); q[4].pop(); add1(th[2]); add2(th[4]);
		}else{
			q[3].pop(); q[4].pop(); add0(th[3]); add2(th[4]);
		}ans += minn;
	}
	printf("%lld\n",ans);
	for(int i = 1;i <= n;i++) printf("%d",vis[i]);
	puts("");
	return 0;
}
posted @ 2021-02-15 20:00  Werner_Yin  阅读(68)  评论(0编辑  收藏  举报