Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

ゲームの攻略

あなたは所属するプログラミング部の部室から古びたボードゲームを発見しました。面白そうなので遊んでみることにしました。

このゲームは M 個のイベントから成り、時刻 ti にイベント i を攻略しなければいけません。ただし、そのときにあなたの強さは si 以上である必要があり、si 以上にできない場合はゲームオーバーになります。ゲーム開始時（時刻０）のあなたの強さは０ですが、アイテムを買うことで強さを増加させることができます。ゲーム開始時のあなたの所持金は０ですが、１単位時間あたり１増加します。

ボードにはそれぞれ１から N の番号が付けられた N 個のアイテムが順番に並べられており、アイテム i の値段は vi で、それを購入するとあなたの強さが hi 増加します。アイテムは所持金が十分であれば好きな時刻に好きな数だけ購入することができますが、残っているアイテムの中で番号が小さいものから順に選ばなければなりません。各アイテムは１度購入すると消滅します。

また、同じ時刻に複数のアイテムを連続で買うことができ、このとき隣り合うアイテムの hi の差分の和をボーナスとして得ることができます。例えば、ある時刻にアイテム１,２,３を同時に買った場合、h1 + h2 + h3 に加えて|h1 - h2| + |h2 - h3| だけあなたの強さが増加します。

あなたは、全てのイベントを攻略した後の所持金を最大化したいと考えています。

アイテムの情報とイベントの情報を入力とし、すべてのイベントを攻略した後の所持金の最大値を出力するプログラムを作成せよ。

Input

入力は以下の形式で与えられる。

N M
v1 h1
v2 h2
:
vN hN
t1 s1
t2 s2
:
tM sM

１行目にアイテムの数 N (1 ≤ N ≤ 3000) とイベントの数 M (1 ≤ M ≤ 1000) が与えられる。続く N 行にアイテム i の値段 vi と強さの増加量 hi (1 ≤ vi, hi ≤ 100000) が与えられる。続く M 行にイベント i の時刻 ti と条件 si (1 ≤ ti, si ≤ 100000) が与えられる。ただし、i < j のとき、ti < tj とする。入力はすべて整数で与えられる。

Output

所持金の最大値を１行に出力する。ただし、攻略することができない場合には「-1」を出力する。

Sample Input 1

5 4
3 3
2 1
1 5
4 2
2 6
4 1
8 2
10 4
12 17

Sample Output 1

2

Sample Input 2

5 4
3 3
2 1
1 5
4 2
2 6
4 1
8 2
10 4
12 30

Sample Output 2

-1

Solution in Scala (judge verdict: Wrong Answer)

object Main extends App {

  import scala.io.StdIn._
  import scala.math._

  val Array(n, m) = readLine.trim.split(' ').map(_.toInt)
  val items = Array.tabulate(n){_ ⇒
    val Array(v, h) = readLine.trim.split(' ').map(_.toInt)
    Item(v, h)
  }
  val itemInfo = new ItemInfo(items)
  println(
    search(m, itemInfo) match {
      case Some(r) ⇒ r
      case None ⇒ -1
    }
  )

  def search(m: Int, itemInfo: ItemInfo, onusSum: Int = 0, currentWholePower: Int = 0, prevBuy: Int = -1, prevCanBuy: Int = -1, lastTime: Int = 0): Option[Int] = {
    if (m == 0){
      Some(lastTime - itemInfo.costToBuyTo(prevBuy))
    }else {
      val Array(t, s) = readLine.trim.split(' ').map(_.toInt)
      if (currentWholePower - onusSum < s) {
        val mustBuy = itemInfo.mustBuy(s + onusSum)
        val canBuy = itemInfo.maxItemCanBuy(t)
        if (mustBuy > canBuy) None
        else if (m == 1){
          search(m - 1, itemInfo, onusSum, currentWholePower, mustBuy, prevCanBuy, t)
        }
        else {
          val minOnusItem = (mustBuy to canBuy).minBy(it ⇒ itemInfo.onusStopBuyTo(it))
          if (minOnusItem <= prevCanBuy) {
            //minOnusItemまで買う
            search(m - 1, itemInfo, onusSum, itemInfo.wholeStrengthTo(minOnusItem), minOnusItem, canBuy, t)
          } else {
            search(m - 1, itemInfo, onusSum + (if (prevBuy >= 0) itemInfo.onusStopBuyTo(prevBuy) else 0), itemInfo.wholeStrengthTo(minOnusItem), minOnusItem, canBuy, t)
          }
        }
      } else {
        search(m - 1, itemInfo, onusSum, currentWholePower, prevBuy, prevCanBuy, t)
      }
    }
  }

  class ItemInfo(private val items: Array[Item]) {
    //cost(i) => 0 to i までのアイテムの購入コストの合計
    private val cost = items.map{_.cost}.also{it ⇒ for (i ← 1 until it.length) it(i) += it(i - 1)}
    //bonus(i) => items(i)とitems(i + 1)を同時に勝った場合のボーナス
    private val bonus = items.map{_.benefit}.also{it ⇒
      for (i ← 1 until it.length)
        it(i - 1) = abs(it(i) - it(i - 1))
      it(it.length - 1) = 0
    }
    //strength(i) => 0 to iまでのアイテムをすべて一度に買った場合の強さの増加分
    private val strength = items.map{_.benefit}.also{it ⇒ for (i ← 1 until it.length) it(i) += it(i - 1) + bonus(i - 1)}
    def maxItemCanBuy(money: Int): Int = upperBound(cost, money) - 1
    def mustBuy(strong: Int): Int = lowerBound(strength, strong)
    def wholeStrengthTo(item: Int): Int = strength(item)
    def onusStopBuyTo(item: Int): Int = bonus(item)
    def costToBuyTo(item: Int): Int = cost(item)
  }
  def upperBound[T](array: Array[T], value: T)(implicit ordering: Ordering[T]): Int = {
    var left = 0
    var right = array.length
    while (left < right){
      val mid = (left + right) / 2
      if (ordering.compare(array(mid), value) <= 0){
        left = mid + 1
      }else {
        right = mid
      }
    }
    right
  }
  def lowerBound[T](array: Array[T], value: T)(implicit ordering: Ordering[T]): Int = {
    var left = 0
    var right = array.length
    while (left < right){
      val mid = (left + right) / 2
      if (ordering.compare(array(mid), value) < 0){
        left = mid + 1
      }else {
        right = mid
      }
    }
    right
  }

  case class Item(cost: Int, benefit: Int)

  implicit class Extention[T](val value :T){
    def also(func: T ⇒ Unit): T = {
      func(value)
      value
    }
    def let[R](func: T ⇒ R): R = func(value)
  }
}