M - おまかせ image

  • 考えたこと
  • 公式解説
    • 比率を直接最大化するのではなく、比率がXを超えるかの判定問題にする
    • これはO(NlogN)で判定できる
    • 比率の取りうる範囲について二分探索すればよい
    • 和の比率の最大化
  • 時間をおいて考えたこと
    • Nが1000なので2^Nの全探索は無理
    • 貪欲に「大きくなるものを足していく」ではダメか?
      • 「X1 < X1 + X2 なら X1 + X3 < X1 + X2 + X3」ならOK python
from random import randint
for i in range(1000):
    a, b, c, d, e, f = [randint(1, 10) for i in range(6)]
    if a / b < (a + c) / (b + d) and (a + e) / (b + f) > (a + c + e) / (b + d + f):
        print(a, b, c, d, e, f)
        break
    - 反例あっさり見つかった: 5 8 5 7 8 7
- [[和の比率の最大化]]をベースに考える
- Xを超えるかどうかの判定問題にする
    - $B_i - X A_i$の符号判定問題
    - Mから最大のものを1つ選ぶ
        - すべて負なら「選ばない」の0が最大
    - ソートして最も大きいものが正ならOK
    - [[二分探索]]
  • 3WA python
def solve(N, M, AS, BS, CS, DS):
    left = 0.0
    right = 1000000.0
    while left < right - 10 ** -7:
        x = (left + right) / 2
        y = max(DS[i] - x * CS[i] for i in range(M))
        zs = list(sorted([BS[i] - x * AS[i] for i in range(N)], reverse=True))
        if y > 0:
            y = y + sum(zs[:4])
        else:
            y = sum(zs[:5])

        if y >= 0:
            left = x
        else:
            right = x
    return left
- rightは10001で良いはず、多めに1000000にしたが変化なし
- left < right - 10 ** -7は要求されてる10 ** -6より小さくしてある
- あ、わかった `if y > 0:`→ `if y > zs[4]:`か
    - →AC
    - 最良のお助けが負のスコアの時「得しないから使わなくて良い」と判断したが「5匹選ばなければならない」という制約によりお助けを選ばない場合にはzs4が選ばれることになるので、こちらがもっと大きなマイナスである可能性がある

誤差を認める問題→二分探索 第一回 アルゴリズム実技検定