BZOJ2832 : 宅男小C
首先将所有显然不在最优解中的外卖都删去,那么剩下的外卖价格越低,保质期也最短。
考虑三分订外卖的次数,然后贪心求解,每次尽量平均的时候可以做到最优化。
三分的时候,以存活天数为第一关键字,剩余钱数为第二关键字,就能使函数严格上凸,这样才可以保证三分的正确性。
时间复杂度$O(n\log m)$。
#include<cstdio> #include<algorithm> #define N 210 using namespace std; typedef long long ll; typedef pair<ll,ll> PI; ll m,f,l,r,len,m1,m2;PI s1,s2,ans; int n,_n,i,j;struct P{ll p,s;}a[N]; bool cmp(const P&a,const P&b){return a.s==b.s?a.p<b.p:a.s>b.s;} bool cmp2(const P&a,const P&b){return a.s<b.s;} PI cal(ll k){ ll t=m-f*k,d=0,now=0,j; for(i=1;i<=n;i++){ if(a[i].s>=d)j=min(t/a[i].p/k,a[i].s-d+1),d+=j,now+=j*k,t-=j*a[i].p*k; if(a[i].s>=d)j=min(t/a[i].p,k),d++,now+=j,t-=j*a[i].p; } return PI(now,t); } int main(){ while(~scanf("%lld%lld%d",&m,&f,&n)){ for(i=1;i<=n;i++)scanf("%lld%lld",&a[i].p,&a[i].s); _n=n,sort(a+1,a+n+1,cmp); for(l=a[j=1].p,i=2;i<=n;i++){ l=min(l,a[i].p); if(a[i].s<=a[j].s&&a[i].p>a[j].p)_n--,a[i].s=-1;else j=i; } sort(a+1,a+n+1,cmp),n=_n,sort(a+1,a+n+1,cmp2); l=1,r=m/(f+a[1].p); while(l<=r){ len=(r-l)/3; if((s1=cal(m1=l+len))>(s2=cal(m2=r-len)))ans=max(ans,s1),r=m2-1;else ans=max(ans,s2),l=m1+1; } printf("%lld\n",ans.first); ans=PI(n=0,0); } return 0; }