【题解】 CF436E Cardboard Box 带悔贪心

Legend

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

(1 le n le 3 imes 10^5)(1 le a_i < b_i le 10^9)(1 le w le 2n)

Link ( extrm{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
" ,ans);
	for(int i = 1 ; i <= n ; ++i)
		printf("%d" ,(vis[i] & 1) + ((vis[i] >> 1) & 1));
	puts("");

	return 0;
}

// very nice greedy problem
原文地址:https://www.cnblogs.com/imakf/p/14321454.html