题解 CF865B Ordering Pizza

Posted win10crz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 CF865B Ordering Pizza相关的知识,希望对你有一定的参考价值。

可能大家都没理解这题的意思,翻译和原文都比较含糊,我来用人话说一遍:

(n) 个人一起去买披萨。披萨店有两种披萨,每种的每个披萨都可以分成 (s) 片。每个人买不同数量的披萨(以片为单位),不同的人买不同种类的披萨所获得的快乐值不同。问在买披萨数量最小的情况下,如何分配买 1 号披萨和 2 号披萨的数量,使获得的快乐值总和最大。


单纯不懂题意的 dalao 到这里就可以结束了,接下来就是分析了

这题我们可以用贪心的思路来做,把买披萨的人分为两类:买 1 号披萨快乐值多的,和买 2 号披萨快乐值多的。然后分别解决两边的情况。当每片披萨的块数不能被这两类的数量分别整除时,就要确定剩下的人买 1 号披萨还是买 2 号披萨。

这里就是最麻烦的地方,我们将两类人按照两种披萨的差价排序,从小到大将剩下的块数补上,分别计算两种方法的损失,然后就按照损失小的方案输出。

高高兴兴的打出了代码:

#include<bits/stdc++.h>
using namespace std;
#define rg register
struct node
{
	long long num,val;    //num 为这个人需要的块数,val 为差价。 
}x[100005],y[100005];     //两类人。 
long long n,s,ans,m,a,b,cnt1,cnt2,sum1,sum2;
long long loss1,loss2;   //不同方案的损失。 
inline bool cmp(node x,node y)
{
	return x.val<y.val;   //按差价从小到大排序。 
}
int main()
{
	cin>>n>>s;
	for(rg int i=1;i<=n;++i)
	{
		cin>>m>>a>>b;
		if(a>b)         //买第一种更开心。 
		{
			x[cnt1].num=m;
			x[cnt1].val=a-b;
			++cnt1;
			sum1+=m;    //计算买第一种的人的总块数。 
			ans+=a*m;   //计算理想值。 
		}
		else            //同上。 
		{
			y[cnt2].num=m;
			y[cnt2].val=b-a;
			++cnt2;
			sum2+=m;
			ans+=b*m;
		}
	}
	sum1%=s;     
	sum2%=s;          //求剩下的孤零零的披萨。 
	sort(&x[0],&x[cnt1],cmp);
	sort(&y[0],&y[cnt2],cmp);
	for(rg int i=0;i<cnt1;++i)   //分别计算损失。 
	{
		if(sum1>=x[i].num)     //孤零零的披萨还有: 
		{
			sum1-=x[i].num;     //抱团。 
			loss1+=x[i].val*x[i].num;    //减去损失。 
		}
		else     //没有了! 
		{
			loss1+=sum1*x[i].val;
			break;      //计算,然后跳出。 
		}
	}
	for(rg int i=0;i<cnt2;++i)   //同上。 
	{
		if(sum2>=y[i].num)
		{
			sum2-=y[i].num;
			loss2+=y[i].val*y[i].num;
		}
		else
		{
			loss2+=sum2*y[i].val;
			break;
		}
	}
	cout<<ans-min(loss1,loss2);   //挑最优的方案。 
	return 0;
} 

然后:

悲催的评测结果

第一个点就 WA 了……


为什么?其实我们忽略了一种情况,就是两种剩下的总和大于 (s),这时候无论怎么做都还要两块披萨,那就豪一把,直接一种一块披萨(答案就是理想值):

	if(sum1+sum2>s)
	{
	   cout<<ans;
	   return 0;
	}

绿了!


高清 AC 无注释代码:

#include<bits/stdc++.h>
using namespace std;
#define rg register
struct node
{
	long long num,val;
}x[100005],y[100005];
long long n,s,ans,m,a,b,cnt1,cnt2,sum1,sum2;
long long loss1,loss2;
inline bool cmp(node x,node y)
{
	return x.val<y.val;
}
int mian()
{
	cin>>n>>s;
	for(rg int i=1;i<=n;++i)
	{
		cin>>m>>a>>b;
		if(a>b)
		{
			x[cnt1].num=m;
			x[cnt1].val=a-b;
			++cnt1;
			sum1+=m;
			ans+=a*m;
		}
		else
		{
			y[cnt2].num=m;
			y[cnt2].val=b-a;
			++cnt2;
			sum2+=m;
			ans+=b*m;
		}
	}
	sum1%=s;
	sum2%=s;
	if(sum1+sum2>s)
	{
	   cout<<ans;
	   return 0;
	}
	sort(&x[0],&x[cnt1],cmp);
	sort(&y[0],&y[cnt2],cmp);
	for(rg int i=0;i<cnt1;++i)
	{
		if(sum1>=x[i].num)
		{
			sum1-=x[i].num;
			loss1+=x[i].val*x[i].num;
		}
		else
		{
			loss1+=sum1*x[i].val;
			break;
		}
	}
	for(rg int i=0;i<cnt2;++i)
	{
		if(sum2>=y[i].num)
		{
			sum2-=y[i].num;
			loss2+=y[i].val*y[i].num;
		}
		else
		{
			loss2+=sum2*y[i].val;
			break;
		}
	}
	cout<<ans-min(loss1,loss2);
	return 0;
} 

逃(

以上是关于题解 CF865B Ordering Pizza的主要内容,如果未能解决你的问题,请参考以下文章

C - Ordering Pizza CodeForces - 867C 贪心 经典

CodeForces 867C Ordering Pizza 贪心,思维

Codeforces Round #437 C. Ordering Pizza

Codeforces Round #437 (Div. 2, based on MemSQL Start[c]UP 3.0 - Round 2) C. Ordering Pizza

题解PIZZA 贪心

每日cf计划