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
5 0
10 2
Sample Output
3
HINT
【样例说明】
JYY的最佳策略是:
第一天买一份食物1和一份食物2并且吃一份食物1;
第二天吃一份食物2;
第三天买一份食物1并且吃掉。
【数据规模与约定】
对于100%的数据满足0<=Si<=10^18,1<=F,Pi,M<=10^18,1<=N<=200
注意到又贵保质期又短的食物是不可能被买的,所以先把它们去掉。
再注意到当买食品的天数确定的时候,可以用贪心法求出最多可以宅多少天,因为此时食品已经被上一步处理成保质期越长越贵,所以越平均地买越好。
当买食品的天数太少时,可能因为没有保质期长的食品或保质期长的食品贵,不能得到很好的答案。而当买食品的天数太多时,可能因为送外卖的费用太高而不能得到很好的答案,所以我们猜在买x天食品的情况下最多宅的天数是关于x的先增后减的单峰函数(严格证明我也不会),用三分法就可以求最值了。
1 program food(input,output); 2 var 3 p,s:array[0..220]of int64; 4 i,j,n:longint; 5 m,f,l,r,lmid,rmid,d,x,y:int64; 6 flag:array[0..220]of boolean; 7 k:int64; 8 function max(a,b:int64):int64; 9 begin 10 if a>b then exit(a) else exit(b); 11 end; 12 function min(a,b:int64):int64; 13 begin 14 if a<b then exit(a) else exit(b); 15 end; 16 procedure swap(var a,b:int64); 17 var 18 t:int64; 19 begin 20 t:=a;a:=b;b:=t; 21 end; 22 procedure sort(q,h:longint); 23 var 24 i,j:longint; 25 x:int64; 26 begin 27 i:=q;j:=h;x:=p[(i+j)>>1]; 28 repeat 29 while p[i]<x do inc(i); 30 while x<p[j] do dec(j); 31 if i<=j then 32 begin 33 swap(p[i],p[j]);swap(s[i],s[j]); 34 inc(i);dec(j); 35 end; 36 until i>j; 37 if j>q then sort(q,j); 38 if i<h then sort(i,h); 39 end; 40 function fun(d:int64):int64; 41 var 42 j:int64; 43 begin 44 x:=m-d*f; 45 y:=x div d; 46 k:=0; 47 for i:=1 to n do 48 begin 49 j:=min(s[i]-k+1,y div p[i]); 50 y:=y-p[i]*j;k:=k+j; 51 //while (s[i]>=k) and (y>=p[i]) do begin inc(k);y:=y-p[i]; end; 52 if y<=p[i] then break; 53 end; 54 if s[n]<k then exit(k*d); 55 if s[i]<k then inc(i); 56 exit(k*d+(y*d+x mod d) div p[i]); 57 end; 58 begin 59 assign(input,'food.in');assign(output,'food.out');reset(input);rewrite(output); 60 readln(m,f,n); 61 for i:=1 to n do readln(p[i],s[i]); 62 fillchar(flag,sizeof(flag),true); 63 for i:=1 to n do 64 for j:=1 to n do if (i<>j) and flag[j] then if (p[i]>=p[j]) and (s[i]<=s[j]) then begin flag[i]:=false;break; end; 65 j:=0; 66 for i:=1 to n do if flag[i] then begin inc(j);p[j]:=p[i];s[j]:=s[i]; end; 67 n:=j; 68 sort(1,n); 69 l:=1;r:=m div f; 70 if r=0 then begin write(0);close(input);close(output);halt; end; 71 while l<r-2 do 72 begin 73 d:=(r-l) div 3;lmid:=l+d;rmid:=r-d; 74 if fun(lmid)<fun(rmid) then l:=lmid+1 else r:=rmid-1; 75 end; 76 write(max(max(fun(l),fun(l+1)),fun(r))); 77 close(input);close(output); 78 end.