ZR860 扁鹊再世蔡徐坤 (贪心 + 堆)

Description

n n n 位病人,坤坤有 V   m L V \ mL V mL 镇静剂。第 i i i 位病人的紧急程度为 a i a_i ai,镇静所需剂量至少为 b i b_i bi。若选了 k k k 个病人 c 1 ∼ c k c_1 \sim c_k c1ck,则病人 c j c_j cj 将得到 a c j ∑ i = 1 k a c j × V \frac{a_{c_j}}{\sum_{i=1}^k a_{c_j}} \times V i=1kacjacj×V 的剂量。求最多稳定的病人数。

1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105

Solution

a i a_i ai b i b_i bi V V V 计算出病人稳定能接受的最大的 ∑ i = 1 k a c j \sum_{i=1}^k a_{c_j} i=1kacj,记作 S i S_i Si。根据 S i S_i Si 将病人从大到小排序。在排序后的病人中,从头枚举一个 k k k 作为 S S S 最小的人,那么 S i S_i Si 比它大的人再保证加上 a i a_i ai 后不超过 S k S_k Sk 的前提下是可选的,可以发现随着 k k k 越来越小,能加入的病人也越来越多。所以维护一个数据结构,能插入一个数,维护最小元素让它们总和不超过 S k S_k Sk,上大根堆即可。如果当前的总和超过 S k S_k Sk 就不断弹出。

Code

#include<bits/stdc++.h>
using namespace std;
struct node{
	int a, b;
	double maxsum;
}d[200001];
priority_queue <int, vector<int>, less<int> > q;
bool cmp(node a, node b){
	return a.maxsum > b.maxsum;	
} 
int n, V, ans, cnt;
long long sum;
int main(){
	scanf("%d%d", &n, &V);
	for (int i = 1; i <= n; i++) 
		scanf("%d%d", &d[i].a, &d[i].b), d[i].maxsum = (double)V * (double)d[i].a / (double)d[i].b;
	sort(d + 1, d + n + 1, cmp);
	for (int i = 1; i <= n; i++){
		sum += d[i].a; cnt++;
		q.push(d[i].a);
		while(sum > d[i].maxsum){
			sum -= q.top(); q.pop();
			cnt--;
		}
		ans = max(ans,cnt);
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2020-02-20 11:17  ylxmf2005  阅读(36)  评论(0)    收藏  举报