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 c1∼ck,则病人 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 1≤n≤2×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;
}

浙公网安备 33010602011771号