avatar
fireworks99
keep hungry keep foolish

CodeForces 371C Hamburgers

Description

做一个汉堡需要B(Bread) S(Sausage) C(Cheese)中的一种或多种,给出一个字符串代表配方,给出已有材料,相应材料商店售价,现有资金,问最多能做多少个汉堡?

题目链接

二分

二分实质:对于暴力枚举的优化

为什么会想到用二分?

  1. 若想枚举出所有情况:太多且易遗漏
  2. 已知答案必在某个固定区间里(此时遍历耗时则用二分优化)

明确目的:

  1. 最大值?
  2. 最小值?
  3. 最大化最小值?
  4. 最小化最大值?

三要素:

  1. 下界:为了方便,可适当向下调整(求最大值时下界必须实际
  2. 上界:为了方便,可适当向上调整(求最大值时,上界是理想值(白日梦值)
  3. bool judge(ll ans):检查资金是否足够

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int nb, ns, nc, pb, ps, pc;
int B = 0, C = 0, S = 0;
long long money;

bool judge(long long ans)
{
    long long needb = ans * B - nb;
    long long needs = ans * S - ns;
    long long needc = ans * C - nc;
    if(B == 0 || needb < 0)
        needb = 0;
    if(S == 0 || needs < 0)
        needs = 0;
    if(C == 0 || needc < 0)
        needc = 0;
    long long needpay = pb * needb + ps * needs + pc * needc;
    if(needpay <= money)
        return 1;
    else
        return 0;
}

int main()
{
    string s;
    cin >> s;
    int sz = s.size();
    scanf("%d%d%d%d%d%d", &nb, &ns, &nc, &pb, &ps, &pc);
    cin >> money;
    for(int i = 0; i < sz; ++i)
    {
        if(s[i] == 'B')
            B++;
        else if (s[i] == 'S')
            S++;
        else
            C++;
    }
    long long one = B * pb + S * ps + C * pc;
    long long l =  money / one;
    long long r =  money / one + max(nb, max(ns, nc));
    ///找最大值时上界为 幻想值(白日梦值)
    long long mid;
    while(l < r)
    {
        mid = (l + r + 1) >> 1;
        if(judge(mid))///找最大值(二分明确所找最值)
            l = mid;
        else
            r = mid - 1;
    }
    cout << l << '\n';
    return 0;
}

改进:调整上下界

long long one = B * pb + S * ps + C * pc;
    long long l =  money / one;
    long long r =  money / one;
    if(B == 0)
    {
        l += min(ns / S, nc / C);
        r += max(ns / S, nc / C);
    }
    else if(S == 0)
    {
        l += min(nb / B, nc / C);
        r += max(nb / B, nc / C);
    }
    else if(C == 0)
    {
        l += min(nb / B, ns / S);
        r += max(nb / B, ns / S);
    }
    else
    {
        l += min(nb / B, min(ns / S, nc / C));
        r += max(nb / B, max(ns / S, nc / C));
    }

如上,之前在找上下界时,执着于缩小范围,导致

  1. 忽视了分母为0的情况而RE

  2. 遗漏了两种材料都不需要的情况而WA

    后来干脆扩展界线,代码简单还AC了

Site by Baole Zhao | Powered by Hexo | theme PreciousJoy