公式

D - 膨らむ借金の一括返済 / Lump-Sum Repayment of Growing Debt 解説 by harurun4635


\(H_i \gt P\) があればその時点で No です。

各借金は \(H_i + k \times G_i \le P\) であるターン \(k ~ ( 0 \le k)\) に返済できます。\(G_i \gt 0\) ですから、これらから各借金が返済できる区間 \([0, r_i]\) が求まります。


さて、これが求まったあとの問題を考えましょう。結論から言えば「 \(r_i\) が小さい順に返済をしていく」という貪欲が正当です。

つまり \(r_0 \le r_1 \le \cdots \le r_{N-1}\) と昇順に並べた時に、すべての \(i\) で \(i \le r_i\) が成り立てばよいです。

証明

ターン \(k\) までには \(k + 1\) 回しか返済のチャンスはありません。つまり、\(r_i \le k\) である \(i\) が \(k+1\) 個以下であることが必要です。よって、 \(r_k \le k\) が必要です。
これがすべての \(k\) で成り立つことが必要ですから、上の条件は必要条件です。

逆に、上のように返済すれば、実際に返済できますから、これは十分条件でもあります。


実装例

実際には \(H_i \gt P\) の条件は処理しなくても正当に動作します。( \(r_i\) を除算で求めた時に、負になるからです)ただし、 C++ などの言語では整数除算が \(0\) 方向に丸められることには注意してください。(先に処理しておくほうが間違いが起こりにくいです)

n, p = map(int, input().split())

r = []
for i in range(n):
    h, g = map(int, input().split())
    r.append(((p - h) // g))

r.sort()
if all(i <= r[i] for i in range(n)):
    print("Yes")
else:
    print("No")

投稿日時:
最終更新: