CodeForces-867C Ordering Pizza 贪心+优先队列

本文介绍了一种优化饼分配的算法,旨在确保每个人获得最大欢乐值的同时,使用的饼张数最少。通过优先队列来实现饼类型的高效转换,以达到整体欢乐值最大化。

题意:

第一行给定n,m; n表示有n个人,m表示一张饼可以分成多少片

接下来n行表示n个人的信息,每行输入s,a,b;s表示这个人要吃s片饼,第一种类型的每片获得欢乐值a,第二种类型的每片获得b;

问保证他们吃的的大饼的‘’张数‘’最少的情况下,获得的最大欢乐值是多少;  注意“张”和“片”的关系,

思路:

首先要知道最少需要的大饼张数是多少,这个数量是 所有人需要的饼的数量加和÷每张饼可分成的片数。如果有余数当然要加一。

然后我们每个人都从a,b中选择快乐值较大的那个,这样会得到需要第一种类型的饼的数量和第二种类型的饼的数量,然后跟最小的饼需求量比较,如果比最小需求饼的数量大,那肯定要选择一些类型的饼换成另一种类型的饼;

要选哪些改变呢?自然是选择那些让当前快乐值尽量小的,这就需要用到优先队列,来储存a和b两种类型饼的快乐值的差值,因为我们还要分析把那种类型的饼改变,所以我们需要两个优先队列分别储存选的是那种类型的饼的差值

 

 

#include<bits/stdc++.h>
#define FI first
#define SE second

using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;


ll n, m;
ll num = 0, num1 = 0, num2 = 0;
ll ans = 0;
priority_queue<P, vector<P>, greater<P> > p1, p2;

void init() {
    for(int i = 1; i <= n; ++i) {
        ll s, a, b;
        scanf("%lld%lld%lld", &s, &a, &b);
        num += s;
        if(a >= b) {
            num1 += s;
            ans += s*a;
            p1.push(P(a-b, s));
        }
        else {
            num2 += s;
            ans += s*b;
            p2.push(P(b-a, s));
        }
    }
}
void solve() {
    ll tmp1 = 0, tmp2 = 0;
    // a -> b
    ll t = num1%m;
    while(!p1.empty()) {
        P x = p1.top(); p1.pop();
        if(t >= x.SE) {
            tmp1 += x.FI*x.SE;
            t -= x.SE;
        }
        else {
            tmp1 += t*x.FI;
            break;
        }
    }
    // b -> a
    t = num2%m;
    while(!p2.empty()) {
        P x = p2.top(); p2.pop();
        if(t >= x.SE) {
            tmp2 += x.FI*x.SE;
            t -= x.SE;
        }
        else {
            tmp2 += t*x.FI;
            break;
        }
    }
    printf("%lld", ans-min(tmp1, tmp2));
}
int main() {
    scanf("%lld%lld", &n, &m);
    init();
    ll t = (num/m + (num%m == 0 ? 0 : 1));
    ll t1 = (num1/m + (num1%m == 0 ? 0 : 1));
    ll t2 = (num2/m + (num2%m == 0 ? 0 : 1));
    if(t1 + t2 > t) {
        solve();
    }
    else {
        printf("%lld", ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值