BZOJ 3874: [Ahoi2014]宅男计划

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

posted on 2016-03-05 20:40  wuyuhan  阅读(834)  评论(0编辑  收藏  举报

导航