N, W = gets.split.map(&:to_i)
items = (1..N).map { gets.split.map(&:to_i) }.sort_by {|v, w| - v.to_f / w }

def search(items, i, v_sum, w_sum, limit, best)
  return v_sum if i >= items.size
  return best if upper_bound(items, i, v_sum, w_sum, limit) <= best
  v, w = items[i]
  if (w_sum + w <= limit)
    best = [search(items, i + 1, v_sum + v, w_sum + w, limit, best), best].max
  end
  return [search(items, i + 1, v_sum, w_sum, limit, best), best].max
end

def upper_bound(items, i, v_sum, w_sum, limit)
  items[i..-1].each do |v, w|
    if w_sum + w <= limit
      w_sum += w
      v_sum += v
    else
      return v_sum + v.to_f * (limit - w_sum) / w
    end
  end
  v_sum
end

p search(items, 0, 0, 0, W, -Float::INFINITY)
