bzoj3874 宅男计划 三分 贪心
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3874
题意:有许多种食品,每种有价格、保质期两种属性,一个人有一个数目的钱,求这个人可以活多久。
如果数据范围小一点那这个显然可以$DP$……然而$0<=Si<=(10^{18}),1<=F,Pi,M<=(10^{18}),1<=N<=200$……我也很绝望啊……
首先这个东西是个凸函数(为什么?我不知道联想生活实际),也就是存活天数是与送餐次数成凸函数(其实不是严格单峰,但在本题可以忽略),那么我们显然可以三分求出最大函数值。
问题变为给出一个$x$,如何求出一个$y$。
根据贪心原则,保质期短价格贵的直接扔掉,于是我们先预处理一下,预处理完之后我们就挨个购买,考虑这个东西每次可以购买的数量。注意最后可能还剩下一些钱够买几次但是不足够每次都买,这一部分也要加以考虑。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=205; 7 struct food 8 { 9 long long p,s; 10 }fin[maxn],sta[maxn]; 11 inline bool comp(const food &x,const food &y) 12 { 13 if(x.s!=y.s)return x.s<y.s; 14 return x.p<y.p; 15 } 16 inline bool cmp(const food &x,const food &y) 17 { 18 return x.p<y.p; 19 } 20 long long m,f;int p,n; 21 inline long long F(long long val) 22 { 23 long long tmp=m-f*val,day=0,ans=0; 24 if(tmp<0)return 0; 25 for(int i=1;i<=p;i++) 26 { 27 if(fin[i].s>=day) 28 { 29 long long con=fin[i].s-day+1ll; 30 long long liv=min(con,tmp/(fin[i].p*val)); 31 ans+=liv*val;day+=liv;tmp-=fin[i].p*val*liv; 32 } 33 if(fin[i].s>=day) 34 { 35 long long liv=min(val,tmp/fin[i].p); 36 ans+=liv;day++;tmp-=fin[i].p*liv; 37 } 38 } 39 return ans; 40 } 41 int haha() 42 { 43 scanf("%lld%lld%d",&m,&f,&n); 44 for(int i=1;i<=n;i++)scanf("%lld%lld",&sta[i].p,&sta[i].s); 45 sort(sta+1,sta+n+1,comp);p++,fin[p]=sta[1]; 46 for(int i=1;i<=n;i++) 47 if(fin[p].s<sta[i].s)p++,fin[p]=sta[i]; 48 sort(fin+1,fin+p+1,cmp); 49 long long l=1,r=m/(f+fin[1].p); 50 long long ans=max(F(l),F(r)); 51 while(r-l>=10) 52 { 53 long long mid1=l+(r-l+1)/3,mid2=r-(r-l+1)/3; 54 if(F(mid1)<F(mid2))l=mid1,ans=max(ans,F(mid1)); 55 else r=mid2,ans=max(ans,F(mid2)); 56 } 57 for(long long i=l;i<=r;i++)ans=max(ans,F(i)); 58 printf("%lld\n",ans); 59 } 60 int sb=haha(); 61 int main(){;}
只要是活着的东西,就算是神我也杀给你看。