aacord’s memo

abcを中心にpythonで解いた問題のメモ、整理をしています。緑になった。

abc 145 E: All-you-can-eat (python)

自力AC。解説とは若干違った。むしろ解説がよく分からん。
ぱっと見で01ナップザック問題じゃんとなり、dpするだけなのかと普通の (N*T) の二次元dp を実装したらサンプル3が合わず考えると、T-1 秒までなら T 秒を超えても注文ができるのが原因だと分かる。なのでこれを自然にケアする方法を考えて
注文は T 秒未満、食べきるのは T + max(A) 秒未満になるような a,b の選び方を実装しようと思った。なので dp[i][j] = i 個目まで見たときに j 秒経過しているときの満足度の最大値
として実装した。
しかしこの実装だと

3 60
30 10
30 20
20 30

みたいなケースで T < 60 でないと満足度を加算しないため、
dp[3][80] = dp[2][60] + 30 としてくれないため答えが合わない。
そこで a の昇順でソートすることで解決した。
計算量の仕方はよく分からないが最悪 O(N*(T+max(A))) ぐらいじゃないかな
pypy でないと通らなかった。

import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
n,t = map(int,readline().split())
f = []
m = 0
for i in range(n):
  p,q = map(int,readline().split())
  m = max(m,p)
  f.append((p,q))
  
f.sort() # sort
dp = [[0]*(t+m) for i in range(n+1)]

for i,c in enumerate(f):
  a,b = c
  for j in range(t+m):
    if j-a >= t: # 注文できるのは T 秒未満のときだけ
      break
    if j < a : # この辺は普通の01ナップザックと同じ
      dp[i+1][j] = dp[i][j]
    else:
      dp[i+1][j] = max(dp[i][j],dp[i][j-a]+b)
      
print(max(dp[n]))