[AHOI2014/JSOI2014]宅男计划
链接:https://www.luogu.com.cn/problem/P4040
题目描述:有\(n\)个食物,每个食物有一个价格\(p_{i}\)和一个保质期\(s_{i}\),\(JYY\)每天都要吃一个食物,它可以通过向外买小哥点外卖来获取食物,每叫一次外卖就要付\(f\)元。问若\(JYY\)有\(M\)元,他最多能吃多少天的外卖。
题解:我们可以三分外卖小哥来的次数。现在就只用考虑外卖小哥来\(k\)次所能吃的最大天数了。
考虑对于一个价格为\(p_{i}\),保质期为\(s_{i}\)的食物与一个价格为\(p_{j}\),保质期为\(s_{j}\)的食物,若\(p_{i}<=p_{j}\)且\(s_{i}>=s_{j}\),那么选\(j\)就不如选\(i\),所以我们可以排除掉这样的食物,可以按\(s\)排序后用单调栈维护。
现在\(p\)与\(s\)都可以满足单调递增了,由于我们选择肯定是先吃是先吃\(s\)尽量小的,先买也是先买\(p\)尽量小的,所以我们可以从左到右依次买,买到买不了这一个时再买下一个,依次加入\(k\)个外卖小哥的贡献中。
但这样可能出现这这\(k\)个外卖小哥的贡献各不相同,但我们仔细想可以发现,加入\(k\)个外卖小哥的贡献各不相同,那么这一个食物一定是你最后买的,因为你没法买满这个食物,就更没法买满下一个价格比它更大的食物了。
复杂度\(O(nlogn)\)
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
long long p,s;
bool operator < (const node &a)const
{
return s<a.s;
}
};
node point[600001];
long long n,f,m,deque[600001];
long long F(__int128 x)
{
__int128 maxn,lst=0,cnt=0,M;
M=m-f*x;
if (M<0)
return -1;
int top=0;
for (int i=1;i<=n;++i)
{
while (point[deque[top]].p>=point[i].p)
top--;
deque[++top]=i;
}
for (int i=1;i<=top;++i)
{
maxn=min(M/point[deque[i]].p,(point[deque[i]].s-lst+1)*x);
if (maxn<=0)
break;
M-=maxn*point[deque[i]].p;
lst+=maxn/x;
cnt+=maxn;
}
return cnt;
}
signed main()
{
long long ans=0;
__int128 first,last,mid,mid2;
cin>>m>>f>>n;
first=1;
last=m/f;
for (int i=1;i<=n;++i)
cin>>point[i].p>>point[i].s;
sort(point+1,point+n+1);
while (first<=last)
{
mid=first+(last-first)/3;
mid2=last-(last-first)/3;
if (F(mid)<F(mid2))
{
first=mid+1;
ans=max(ans,F(mid));
}
else
{
last=mid2-1;
ans=max(ans,F(mid2));
}
}
cout<<ans<<endl;
return 0;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983652.html

浙公网安备 33010602011771号