N=1000,Y=1234000 のとき、たとえば10000円札、5000円札、1000円札がそれぞれ14枚、27枚、959枚あれば、合計1000枚で
10000∗14+5000∗27+1000∗959=1234000
となり、条件を満たす。また、26枚、0枚、974枚でも条件を満たす。どれを答えてもよい。
1≤N≤2000 なので、全部調べればいける
# 擬似コード for x in 0 .. N: for y in 0 .. N-x: if 10000 * x + 5000 * y + 1000 * (N-x-y) == Y: # 発見! # ループ終了まで発見できない場合、NとYが不可能な組み合わせである
鶴亀算の要領で差分を利用すると、計算量を減らせる
あとは、この x,y を1つずつ調べればよい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def solve(n, y): tmp1000 = n * 1000 if tmp1000 > y: return - 1 , - 1 , - 1 diff = y - tmp1000 for y in range (diff / / 4000 + 1 ): tmp5000 = y * 4000 if diff - tmp5000 < 0 : break if (diff - tmp5000) % 9000 = = 0 : x = (diff - tmp5000) / / 9000 if x > = 0 and x + y < = n: return x, y, n - x - y return - 1 , - 1 , - 1 print ( * solve( * map ( int , input ().split()))) |
連立方程式から考えると、O(1) で解ける。解説放送参照。
Y′=Y/1000 として、
x+y+z=N10x+5y+z=Y′
ここから、x,y,z が非負整数という条件より、3つの条件式ができる。この条件式を満たす z さえ見つければ、そこから求められる x,y は必ず条件を満たしている。
0≤z≤min(N,Y)Y′−zは5の倍数N−z≤Y′−z5≤2(N−z)
一番下は、整理すると以下になる。
5N−Y′4≤z≤10N−Y′9
たとえば、N=1000,Y=1234000 なら、
0≤z≤min(1000,1234)=1000z≡4mod55000−12344=941.5≤z≤974=10000−12349
となり、z=944,949,954,... で解を持つことが分かる。
ただ、計算量的に十分間に合うなら、競技プログラミングでは考察・実装にかかる時間が短い方を選択するべきなので、最初の方法でいい。
計算問題だが、考えるべき条件がいくつかある。
とりあえず bi が高い刀から順に投げて、倒せたらそれまでに投げた本数が答え。
投げるだけでは倒せない場合、切ってダメージを与える。投げた後の残りHPを R とすると、ceil(R/amax) で、切る回数が求められる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from math import ceil def solve(h, aa, bb): max_a = max (aa) i = 0 for b in sorted (bb, reverse = True ): if b < = max_a: break i + = 1 h - = b if h < = 0 : return i return i + ceil(h / max_a) n, h = map ( int , input ().split()) aa, bb = [], [] for _ in range (n): a, b = map ( int , input ().split()) aa.append(a) bb.append(b) print (solve(h, aa, bb)) |