Codeforces Round #437 Div. 2 C. Ordering Pizza (贪心经典)

思路来源

https://blog.csdn.net/so_so_y/article/details/78152910

题意

N个人,每个比萨S块,有两种比萨,

每个人i,需要吃披萨si块,吃比萨1会得到ai快乐值,吃比萨2会得到bi快乐值。

在提供比萨数最小,以确保所有人都有比萨吃的情况下,

问最大的快乐值。

题解

先理想化最大收益,然后贪心地使损失最小。

这是贪心题中的一种经典题。

先假设每人都吃的使自己快乐值最大那块,

期间记录下:若改披萨吃则不得不损失的快乐值和对应的块数,

扫描二维码关注公众号,回复: 3444839 查看本文章

分别存进to1(2->1)和to2(1->2)优先队列,按损失快乐值排序,若不得以而损失,先选损失快乐值少的。

最后num1%=s,num2%=s,剩下的不足s的,若加一起超过s说明需要两块,这样最大收益可达。

否则小于s,这样一块比萨就可以满足,即一部分人不得不牺牲选择另一种披萨。

分别枚举这块比萨是比萨1和比萨2,然后统计优先队列里的损失快乐值cost以凑齐块数。

最后答案就是max(ans-cost1,ans-cost2).

心得

很经典的贪心题,

之前也见过这种先贪最大答案,然后一步步,退而求其次的。

先wa一发爆int了可还行,应该超过s就mod s的,就不用开long long了。

代码

#include <iostream>
#include <algorithm> 
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <bitset> 
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;
const int mod=1e9+7;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<ll,ll> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
ll ans,n,s,a[maxn],b[maxn],num1,num2;
priority_queue<pii,vector<pii>,greater<pii> >to1,to2;//to1表示2->1,to2表示1->2 
void init()
{
        ans=0;num1=0;num2=0;
		while(to1.size())to1.pop();
		while(to2.size())to2.pop();
		mem(a,0),mem(b,0);
}
int main()
{
	while(~scanf("%lld%lld",&n,&s))
	{
		init();
		rep(i,0,n-1)
		{
			ll s,a,b;
			scanf("%lld%lld%lld",&s,&a,&b);
			if(a>b)
			{
				num1+=s;
				ans+=s*a;
				to2.push(pii(a-b,s));//表明向2转化的cost,先转化浪费少的 
			} 
			else
			{
				num2+=s;
				ans+=s*b;
				to1.push(pii(b-a,s)); 
			}
		}
			num1%=s,num2%=s;//正好的就用s装,剩下的部分最多两个s就能装得下
			if(num1+num2>s)//需要两个 不需要转化 
			{
				printf("%lld\n",ans);
				continue;
			} 
			else
			{
				ll tmp1=num1,tmp2=num2,cost1=0,cost2=0;
				while(tmp1)//将1全转化为2 
				{
					pii tmp=to2.top();
					to2.pop();
					ll num=min(tmp1,tmp.second);
					tmp1-=num;
					cost1+=num*tmp.first;
				}
				while(tmp2)
				{
					pii tmp=to1.top();
					to1.pop();
					int num=min(tmp2,tmp.second);
					tmp2-=num;
					cost2+=num*tmp.first;
				}
				printf("%lld\n",max(ans-cost1,ans-cost2));
			}
		}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/82925050