zoukankan      html  css  js  c++  java
  • bzoj3874[Ahoi2014]宅男计划

    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.
  • 相关阅读:
    HDU1864--01背包
    HDU4508--完全背包
    HDU5410--01背包+完全背包
    HDU1284--完全背包
    HDU1248--完全背包
    HDU2191--多重背包(二进制分解+01背包)
    HDU2186--水
    PAT乙级--1003
    51Nod--1006 lcs
    51Nod--1008
  • 原文地址:https://www.cnblogs.com/Currier/p/6369761.html
Copyright © 2011-2022 走看看