【連結】h在這裡寫連結
【題意】
給你參賽者的數量以及一個整數S表示每塊披薩的片數。
每個引數者有3個引數,si,ai,bi;
表示第i個參賽者它要吃的披薩的片數,以及吃一片第一種披薩增加的幸福感,
以及吃一片第二種披薩增加的幸福感。
兩種披薩都能任意數量地訂購。
但是總數num有一個上限。
就是S*num>=∑si
且num最小。
也就是說相當於給你一個num;
讓你求兩種披薩各要買多少個a,b(a+b==num)。
使得參賽者的幸福感儘可能高。
(參賽者即可以選擇第一種、也可以同時吃第二種)
每個引數者有3個引數,si,ai,bi;
表示第i個參賽者它要吃的披薩的片數,以及吃一片第一種披薩增加的幸福感,
以及吃一片第二種披薩增加的幸福感。
兩種披薩都能任意數量地訂購。
但是總數num有一個上限。
就是S*num>=∑si
且num最小。
也就是說相當於給你一個num;
讓你求兩種披薩各要買多少個a,b(a+b==num)。
使得參賽者的幸福感儘可能高。
(參賽者即可以選擇第一種、也可以同時吃第二種)
【題解】
如果每個人想要的披薩片數和<=S
那麼只能買一塊披薩。
則買a或買b,那麼每個人都只能選A或選B
取較大值就好。
矛盾點在哪裡?
雖然你的a大,但是已經沒有A披薩給你了
或者,全都買B披薩更合適
列舉最後買了多少個B披薩
i=0
則一開始全都吃A披薩
i=1
則讓B-A前S大的人變成吃B披薩
i=2
則讓B-A前2S大的人變成吃B披薩
在i=i-1的基礎上改一下就好
記錄到了哪一個人,那個人還能有多少從A->B
i最大為num,且i*S<=∑si
以B-A為關鍵字降序排一下?
那麼只能買一塊披薩。
則買a或買b,那麼每個人都只能選A或選B
取較大值就好。
矛盾點在哪裡?
雖然你的a大,但是已經沒有A披薩給你了
或者,全都買B披薩更合適
列舉最後買了多少個B披薩
i=0
則一開始全都吃A披薩
i=1
則讓B-A前S大的人變成吃B披薩
i=2
則讓B-A前2S大的人變成吃B披薩
在i=i-1的基礎上改一下就好
記錄到了哪一個人,那個人還能有多少從A->B
i最大為num,且i*S<=∑si
以B-A為關鍵字降序排一下?
【錯的次數】
0
【反思】
加註釋的方式真的很好。。
【程式碼】
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5;
struct abc{
ll a,b,rest,c;
};
int n;
ll S,temp,num,srest,ans;
abc a[N+10];
bool cmp(abc a,abc b)
{
return a.c > b.c;
}
int main()
{
//freopen("F:\\rush.txt","r",stdin);
scanf("%d%lld",&n,&S);
for (int i = 1;i <= n;i++){
scanf("%lld%lld%lld",&a[i].rest,&a[i].a,&a[i].b);
a[i].c = a[i].b-a[i].a;
temp += a[i].rest*a[i].a;
srest += a[i].rest;
}
//獲取最多買多少個披薩
ll l = 1,r = 1e10 + 100;
while (l <= r)
{
ll mid = (l+r)>>1;
ll temp = mid*S;
if (temp >= srest)
{
num = mid;
r = mid - 1;
}else
l = mid + 1;
}
sort(a+1,a+1+n,cmp);//按照B-A降序排
ans = temp;//一開始全都吃A披薩
//這個num的值可能會很大,你可能不能列舉出來全部。
//在可以的情況下,儘量貪心選。只要B披薩的數目不超過num就可以了
ll temp1 = 0,tnum = 0;//tnum是之前剩餘的變成B更優的個數
//temp1是那些變成B之後答案的遞增值
ll spe = num*S-srest;//多買的披薩的片數
//S片才能湊夠一個B披薩
for (int i = 1;i <= n;i++)
{
//第i個人有一些變成選B披薩
if (a[i].c < 0)//這個人變成B之後答案會減小
{//用spe儘量不讓他減小->本來肯定要有一些人從a變成B,現在可以用多餘的填,不用讓他們變了
//前提是
if (tnum + a[i].rest + spe >= S)//夠湊了
{
ll dd = tnum + spe;
if (dd >= S)//不用加就能超過了
{
ans = max(ans,temp + temp1);
}else
{
ll js = S-dd;
ans = max(ans,temp + temp1 + a[i].c*js);
}
temp1 = 0;
break;
}
}
if (tnum + a[i].rest < S)//如果沒有超過了1塊披薩的量
{
temp1 += a[i].rest*a[i].c;
tnum += a[i].rest;
}else//超過了
{
//這一個人的a->b選了多少個?
temp += temp1;//優先加之前的
ll rr = (a[i].rest + tnum)%S;//剩餘的
ll choose = a[i].rest-rr;//之後再加當前的
temp += choose*a[i].c;
tnum = rr;//前些輪的剩餘變成rr了
temp1 = rr*a[i].c;//temp1變成rr*a[i].c了
ans = max(ans,temp);//取最大值
//顯然這個過程中B是肯定夠用的
}
}
//temp1 = 1;
//printf("%lld\n",temp1);
if (tnum + spe >= S)//全為正數最後一個剩下的可能還可以和多餘的湊出來一個S
{
ans = max(ans,temp + temp1);
}
printf("%lld\n",ans);
return 0;
}