Problem:
Problem E: The Number of the Real Roots of a Cubic Equation

Description

3次方程式： が与えられるので，その正の実数根の個数，負の実数根の個数をそれぞれ調べて欲しい．

根の個数は，重根も含めて数えるものとする．

Input

入力は複数のテストケースからなり，1行目にはその個数が記される．

2行目以降はa b c dの形式で3次方程式の係数が記される．aは0ではなく，またそれぞれの数は-100から100までの整数値である．

Output

与えられた3次方程式に対し，正の実数根の個数，負の実数根の個数をスペースで区切って出力せよ．

Sample Input

2
1 3 3 1
-10 0 0 0

Output for Sample Input

0 3
0 0

Solution in Scala (judge verdict: Accepted)

import scala.annotation.tailrec
import scala.collection.mutable
object Main extends App {
  import scala.io.StdIn._
  val EPS = 0.000000001
  for (_ ← 0 until readInt()) {
    val Array(a, b, c, d) = readLine.trim.split(' ').map(_.toInt)
    val cubic = if (a > 0) CubicEquation(a, b, c, d) else CubicEquation(-a, -b, -c, -d)
    val (positive, negative) = cubic.derivative.root.sorted match {
      case Nil ⇒
        if (cubic(0) == 0) (0, 0)
        else if (cubic(0) < 0) (1, 0)
        else (0, 1)
      case p::Nil ⇒
        if (cubic(0) == 0) (0, 0)
        else if (math.abs(cubic(p)) < EPS) {
          if (p > 0) (3, 0)
          else (0, 3)
        }else {
          if (cubic(0) < 0) (1, 0)
          else (0, 1)
        }
      case l::r::_ ⇒
        val (lp, ln) = binSearch(cubic, -300, l)
        val (mp, mn) = binSearch(cubic, r, l)
        val (rp, rn) = binSearch(cubic, r, 300)
        (lp + mp + rp, ln + mn + rn)
    }
    println(s"$positive $negative")
  }
  def binSearch(cubic: CubicEquation, min: Double, max: Double): (Int, Int) = {
    if (cubic(max) < -EPS || cubic(min) > EPS) (0, 0)
    else if (((min <= 0 && 0 <= max) || (max <= 0 && 0 <= min)) && cubic(0) == 0) (0, 0)
    else {
      var left = min
      var right = max
      while (math.abs(right - left) > EPS) {
        val mid = (left + right) / 2
        if (cubic(mid) >= 0) right = mid
        else left = mid
      }
      if (right > 0) (1, 0)
      else (0, 1)
    }
  }
}
case class CubicEquation(a: Long, b: Long, c: Long, d: Long) {
  def derivative: SquareEquation = SquareEquation(3 * a, 2 * b, c)
  def apply(x: Double): Double = a * x * x * x + b * x * x + c * x + d
}
case class SquareEquation(a: Long, b: Long, c: Long) {
  def root: List[Double] = {
    if (b * b - 4 * a * c < 0) Nil
    else if (b * b == 4 * a * c) List(-b / 2.0 / a)
    else List((-b - math.sqrt(b * b - 4 * a * c)) / 2.0 / a, (-b + math.sqrt(b * b - 4 * a * c)) / 2.0 / a )
  }
}