import java.util.Scanner

object Main extends App { 
  val sc = new Scanner(System.in)
  val N = sc.nextInt()
  val W = sc.nextLong()
  val items = (for (i <- 1 to N) yield (sc.nextLong, sc.nextLong)).toList.sortWith(basicOrder)

  type Item  = (Long, Long) // (value, Weight)
  type Items = List[Item]

  def valuePerWeight(a:Item, b:Item):Boolean = {
    val (va,wa) = a
    val (vb,wb) = b
    va.toDouble/wa > vb.toDouble/wb
  }

  def basicOrder(a:Item, b:Item):Boolean = {
    (a, b) match {
      case ((va,wa),(vb,wb)) if va < vb => true
      case ((va,wa),(vb,wb)) if va == vb && wa < wb => true
      case _ => false
    }
  }

  type ItemCount = (Item, Int)

  def compress(al:Items):Items = {
    def count(list:Items, preItem:ItemCount, ac:List[ItemCount]):List[ItemCount] = {
      if (list.isEmpty) preItem::ac
      else preItem match {
        case (p, c) if list.head == p => count(list.tail, (p,c+1), ac)
        case _ => count(list.tail, (list.head, 1), preItem::ac) 
      }
    }

    def mkItems(t:ItemCount):List[Item] = {
      def iter(v:Long, w:Long, m:Int, s:Int, acc:List[Item]):(Int, List[Item]) = {
        if (m > 1) {
          iter(v << 1,w << 1,m >> 1, s << 1, (v, w)::acc)
        } else (s,acc)
      }
      val ((v,w),m) = t
      val (s, items) = iter(v, w, m, 1, Nil)
      val k = m - (s -1)
      if (k > 0) (v*k,w*k)::items else items
    }

    val cl = count(al, (al.head,0), Nil)
    (for (e <- cl) yield mkItems(e)).flatten.toList.sortWith(valuePerWeight)
  }

// Greedy Knapsack solver. items have to be descending by value per weight.  
  def gks(items:Items, weight:Long):Double = {
    def iter(items:Items, weight:Long, ac:Double):Double = {
      if (items.isEmpty || weight <= 0) ac
      else {
        val (v, w) = items.head
        if (weight < w) ac+v*weight.toDouble/w
        else iter(items.tail, weight -w, ac+v)    
      }
    }
    iter(items, weight, 0f)
  }

  def solver(items:Items, weight:Long):Long = {
    if (items.isEmpty || weight == 0) 0
    else {
      val (v, w)= items.head
      if (weight >= w) {
        val v0 = solver(items.tail, weight-w) + v
        if (v0 < gks(items.tail, weight)) v0 max solver(items.tail, weight)
        else v0
      }
      else solver(items.tail, weight)
    }
  }

  println(solver(compress(items), W))
}
