首页 > 其他 > 详细

bzoj3874[Ahoi2014]宅男计划

时间:2017-02-06 12:37:37      阅读:156      评论:0      收藏:0      [点我收藏+]

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<=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.

 

bzoj3874[Ahoi2014]宅男计划

原文:http://www.cnblogs.com/Currier/p/6369761.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!