题意:
第一行给定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;
}
本文介绍了一种优化饼分配的算法,旨在确保每个人获得最大欢乐值的同时,使用的饼张数最少。通过优先队列来实现饼类型的高效转换,以达到整体欢乐值最大化。
786

被折叠的 条评论
为什么被折叠?



