1. 程式人生 > >Codeforces Round #437 Div. 2 C. Ordering Pizza (貪心經典)

Codeforces Round #437 Div. 2 C. Ordering Pizza (貪心經典)

思路來源

題意

N個人,每個比薩S塊,有兩種比薩,

每個人i,需要吃披薩si塊,吃比薩1會得到ai快樂值,吃比薩2會得到bi快樂值。

在提供比薩數最小,以確保所有人都有比薩吃的情況下,

問最大的快樂值。

題解

先理想化最大收益,然後貪心地使損失最小。

這是貪心題中的一種經典題。

先假設每人都吃的使自己快樂值最大那塊,

期間記錄下:若改披薩吃則不得不損失的快樂值和對應的塊數,

分別存進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;
}