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;
}

  

posted @ 2015-09-29 01:31  Claris  阅读(272)  评论(0编辑  收藏  举报