num, time = gets.chomp.split(" ").map(&:to_i)
time -= 1
things = []
num.times { things << gets.split.map(&:to_i) }

# 許容時間ごとの価値の最大値と食べた料理を格納（順次更新）
dp = Array.new(time + 1)
# [価値, [食べた料理たち]]
(time + 1).times { |i| dp[i] = [0, Array.new] }

# num個目までの料理を、ナップサックに入れるべきか順番に確認する
num.times do |n|
  # n個目の時間をtmp_time、価値をtmp_valueとする
  tmp_time, tmp_value = things[n]
  # 許容時間がtimeからtmp_timeまでの場合を、順番に確認する
  # （許容時間がtmp_time未満の場合、ナップサックに入れることはできないため確認の必要なし）
  # なお、uptoを用いて逆向きに確認すると、ループ中に既に更新した数値を参照してしまうため、正常に動作しない
  time.downto(tmp_time) do |t_accepted|
    # 「許容時間がtmp_time分少ない時の価値 + tmp_value」が「現在格納されている値」よりも大きければ格納する
    # 既に食べた料理をメモしておく
    if dp[t_accepted][0] < dp[t_accepted - tmp_time][0] + tmp_value
      dp[t_accepted][0] = dp[t_accepted - tmp_time][0] + tmp_value
      dp[t_accepted][1] = dp[t_accepted - tmp_time][1] + [n]
    end
  end
end

puts dp[time][0]
exit

used = dp[time][1]

# まだ食べていない料理のうち、最も価値の高い料理を最後に食べる
left_things = things.select.with_index { |t, i| !used.include?(i) }
last_thing = left_things.max_by { |a| a[1] }
# last_value が存在すれば、その価値を足す
puts last_thing ? dp[time][0] + last_thing[1] : dp[time][0]
