BZOJ 3874: [Ahoi2014]宅男计划
标签(空格分隔): OI-BZOJ OI-二分 OI-三分 OI-贪心
Time Limit: 1 Sec
Memory Limit: 256 MB
Description
【故事背景】
自从迷上了拼图,JYY就变成了个彻底的宅男。为了解决温饱问题,JYY
不得不依靠叫外卖来维持生计。
【问题描述】
外卖店一共有N种食物,分别有1到N编号。第i种食物有固定的价钱Pi和保质期Si。第i种食物会在Si天后过期。JYY是不会吃过期食物的。
比如JYY如果今天点了一份保质期为1天的食物,那么JYY必须在今天或
者明天把这个食物吃掉,否则这个食物就再也不能吃了。保质期可以为0天,这
样这份食物就必须在购买当天吃掉。
JYY现在有M块钱,每一次叫外卖需要额外付给送外卖小哥外送费F元。
送外卖的小哥身强力壮,可以瞬间给JYY带来任意多份食物。JYY想知道,在
满足每天都能吃到至少一顿没过期的外卖的情况下,他可以最多宅多少天呢?
Input
第一行包含三个整数M,F和N。
接下来N行,第i行包含两个整数Pi和Si。
Output
输出仅包含一行一个整数表示JYY可以宅的最多的天数。
Sample Input
32 5 2
5 0
10 2
Sample Output
3
HINT
【样例说明】
JYY的最佳策略是:
第一天买一份食物1和一份食物2并且吃一份食物1;
第二天吃一份食物2;
第三天买一份食物1并且吃掉。
【数据规模与约定】
对于100%的数据满足0<=Si<=1018,1<=F,Pi,M<=1018,1<=N<=200
Solution####
二分套三分,先二分答案(天数),三分送餐次数,以需要钱数为关键字比较。
求需要钱数:总天数/送餐次数,可知每次送餐的盒饭数(尽量平均,朴素理解是如果相差盒饭数>=2,那么可以把多的调整到少的,总的天数不变,需要钱数更少)
复杂度(O(log_2n*log_2^2m))
Code####
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<bitset>
#include<vector>
using namespace std;
#define PA pair<double,double>
#define LL long long
long long read()
{
long long s=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
return s*f;
}
//smile please
long double M,F,ma;
int n;
pair<long double,long double>a[205],b[205];;
long double g(LL c)
{
long double sum=F;LL now=0;
for(int i=1;i<=n;i++)
if(min(a[i].first,(long double)c)>now)
sum+=(min(a[i].first,(long double)c)-now)*a[i].second,
now=min(a[i].first,(long double)c);
if(now<c)return M+1;
return sum;
}
long double f(LL day,LL cf)
{
return g(day/cf)*(cf-day%cf)+g(day/cf+1)*(day%cf);
}
bool pan(LL day)
{
LL l=max(day/ma,(long double)1),r=day;
while(l+4<r)
{LL m1=(l+l+r)/3,m2=(l+r+r)/3;
long double f1=f(day,m1),f2=f(day,m2);
if(f1<=M||f2<=M)return 1;
if(f1<f2)
r=m2;
else
l=m1;
}
for(LL i=l;i<=r;i++)
if(f(day,i)<=M)
return 1;
return 0;
}
LL ef(LL l,LL r)
{
if(l==r)return l;
LL mid=l+r+1>>1;
if(pan(mid))
return ef(mid,r);
else
return ef(l,mid-1);
}
bool cmp(PA a,PA b)
{return a.second<b.second;}
int main()
{
M=read(),F=read(),n=read();
for(int i=1;i<=n;i++)
a[i].second=read(),a[i].first=read()+1,
ma=max(ma,a[i].first);
sort(&a[1],&a[n+1],cmp);
cout<<ef(0,M)<<endl;
return 0;
}