Problem:
Exact Arithmetic

Let X be a set of all rational numbers and all numbers of form q√r, where q is a non-zero rational number and r
is an integer greater than 1. Here r must not have a quadratic number except for 1 as its divisor. Also, let X* be a
set of all numbers which can be expressed as a sum of one or more elements in X.

A machine Y is a stack-based calculator which operates on the values in X* and has the instructions shown in the table below.

push n

Pushes an integer specified in the operand onto the stack.

add

Pops two values x1 and x2 from the top of the stack in this order, then pushes (x2 + x1).

sub

Pops two values x1 and x2 from the top of the stack in this order, then pushes (x2 - x1 ).

mul

Pops two values x1 and x2 from the top of the stack in this order, then pushes (x2 × x1 ).

div

Pops two values x1 and x2 from the top of the stack in this order, then pushes (x2 ÷ x1).
x1 must be a non-zero value in X (not X*).

sqrt

Pops one value x from the stack and pushes the square root of x. x must be a non-negative rational number.

disp

Pops one value x from the stack, and outputs the string representation of the value x to the display. The representation rules are stated later.

stop

Terminates calculation. The stack must be empty when this instruction is called.

Table 1: Instruction Set for the Machine Y

A sufficient number of values must exist in the stack on execution of every instruction. In addition, due to the
limitation of the machine Y, no more values can be pushed when the stack already stores as many as 256 values.
Also, there exist several restrictions on values to be pushed onto the stack:

For rational numbers, neither numerator nor denominator in the irreducible form may exceed 32,768 in its absolute value.

For any element in X of the form q√r = (a/b)√r, |a√r| ≤ 32,768 and |b| ≤ 32,768.

For any element in X*, each term in the sum must satisfy the above conditions.

The rules for the string representations of the values (on the machine Y) are as follows:

A rational number is represented as either an integer or an irreducible fraction with a denominator greater
than 1. A fraction is represented as "<numerator>/<denominator>". A sign symbol - precedes in case of a negative number.

A number of the form q√r is represented as "<string representation of q>*sqrt(r)" except for the case
with q = ±1, in which the number is represented as "sqrt(r)" (q = 1) or "-sqrt(r)" (q = -1).

For the sum of two or more elements of X, string representations of all the (non-zero) elements are con-
nected using the binary operator +. In this case, all terms with the same rooted number are merged into a
single term, and the terms must be shown in the ascending order of its root component. For the purpose of
this rule, all rational numbers are regarded to accompany √1.

There is exactly one space character before and after each of the binary operator +. No space character appears at any other place.

The followings are a few examples of valid string representations:

0
1
-1/10
2*sqrt(2) + 1/2*sqrt(3) + -1/2*sqrt(5)
1/2 + sqrt(10) + -sqrt(30)

Your task is to write a program that simulates the machine Y.

Input

The input is a sequence of instructions. Each line contains a single instruction. You may assume that every
instruction is called in a legal way. The instruction stop appears only once, at the end of the entire input.

Output

Output the strings which the machine Y will display. Write each string in a line.

Sample Input

push 1
push 2
sqrt
div
push 1
push 3
sqrt
div
add
disp
push 8
sqrt
push 3
push 2
sqrt
mul
add
disp
stop

Output for the Sample Input

1/2*sqrt(2) + 1/3*sqrt(3)
5*sqrt(2)

Solution in Scala (judge verdict: Accepted)

import Main.Rational.Rational

import scala.annotation.tailrec
import scala.collection.mutable
import scala.io.StdIn._

object Main extends App {

  implicit object ConvertRationalL extends ConvertRational[Long] {
    @inline def toR(that: Long): Rational = Rational(that)
  }
  import Main.Rational._
  val push = """push (-?\d+)""".r
  val prime = primes(1 << 15)
  solve()
  def primes(upper: Int): Array[Int] = {
    val memo = Array.tabulate(upper + 1){_ ⇒ true}
    var i = 3
    for (j ← 4 to upper by 2) memo(j) = false
    while (i * i < upper){
      if (memo(i)){
        for (j ← i * 2 to upper by i){
          memo(j) = false
        }
      }
      i += 2
    }
    (2 to upper).filter(memo).toArray
  }
  @tailrec
  def solve(stack: List[List[Sqrt]] = Nil): Unit = {
    val message = readLine.trim
    message match {
      case "add" ⇒ stack match {
        case x1::x2::xs ⇒ solve(plus(x2, x1)::xs)
        case _ ⇒ ???
      }
      case "sub" ⇒ stack match {
        case x1::x2::xs ⇒ solve(minus(x2, x1)::xs)
        case _ ⇒ ???
      }
      case "mul" ⇒ stack match {
        case x1::x2::xs ⇒ solve(mul(x2, x1)::xs)
        case _ ⇒ ???
      }
      case "div" ⇒ stack match {
        case x1::x2::xs ⇒ solve(div(x2, x1)::xs)
        case _ ⇒ ???
      }
      case "sqrt" ⇒ stack match {
        case (Sqrt(1, r)::Nil)::xs ⇒ solve(List(Sqrt(r))::xs)
        case _ ⇒ ???
      }
      case "disp" ⇒ stack match {
        case Nil::xs ⇒ println(0)
          solve(xs)
        case x::xs ⇒ println(x.mkString(" + "))
          solve(xs)
        case _ ⇒ ???
      }
      case "stop" ⇒ return
      case push(n) ⇒ solve(List(Sqrt(1, Rational(n.toInt)))::stack)
      case _ ⇒ ???
    }
  }
  object Sqrt {
    def apply(rational: Rational): Sqrt = {
      if (rational.numerator == 0) new Sqrt(1, rational)
      else {
        var base = rational.numerator * rational.denominator
        var mul = 1
        var i = 0
        while (prime(i) * prime(i) <= base) {
          while (base % (prime(i) * prime(i)) == 0) {
            mul *= prime(i)
            base /= (prime(i) * prime(i))
          }
          i += 1
        }
        new Sqrt(base, Rational(mul, rational.denominator))
      }
    }

  }
  case class Sqrt (base: Long, multiple: Rational) {
    assert(base != 0)
    def *(that: Sqrt): Sqrt = {
      val g = gcd(base, that.base)
      new Sqrt(base * that.base / g / g, multiple * that.multiple * g)
    }
    def /(that: Sqrt): Sqrt = {
      val g = gcd(base, that.base)
      new Sqrt(base * that.base / g / g, g * multiple / that.multiple / that.base)
    }
    def unary_-(): Sqrt = new Sqrt(base, -multiple)

    override def toString: String = {
      if (base == 1) multiple.toString
      else if (multiple.numerator == multiple.denominator) s"sqrt($base)"
      else if (multiple.numerator == -(multiple.denominator)) s"-sqrt($base)"
      else s"${multiple}*sqrt($base)"
    }
  }
  def plus(x2: List[Sqrt], x1: List[Sqrt]): List[Sqrt] = {
    normalize(x2 ++ x1)
  }
  def minus(x2: List[Sqrt], x1: List[Sqrt]): List[Sqrt] = {
    normalize(x2 ++ x1.map(-_))
  }
  def mul(x2: List[Sqrt], x1: List[Sqrt]): List[Sqrt] = {
    normalize(x2.flatMap(s ⇒ x1.map(s * _)))
  }
  @tailrec
  def div(x2: List[Sqrt], x1:List[Sqrt]): List[Sqrt] = {
    x1 match {
      case s::Nil ⇒ normalize(x2.map(_ / s))
      case _ ⇒ x1.find(_.base != 1) match {
        case Some(s) ⇒
          val ng = x2.map(_.multiple.numerator).reduce(gcd)
          val dg = x1.map(_.multiple.denominator).reduce(gcd)
          val n = x2.map(s ⇒ new Sqrt(s.base, s.multiple / ng * dg))
          val d = x1.map(s ⇒ new Sqrt(s.base, s.multiple / ng * dg))
          val a = d.filter(_.base % s.base == 0)
          val b = d.filterNot(_.base % s.base == 0)
          val diff = minus(b, a)
          div(mul(n, diff), mul(d, diff))
        case None ⇒ ???
      }
    }
  }
  def normalize(terms: List[Sqrt]): List[Sqrt] = {
    val map = mutable.Map[Long, Rational]()
    for (term ← terms){
      if (map.contains(term.base)) {
        map(term.base) += term.multiple
      }else {
        map.put(term.base, term.multiple)
      }
    }
    map.toList.filter(_._2.numerator != 0).sortBy(_._1).map(it ⇒ new Sqrt(it._1, it._2))
  }
  object Rational {

    import scala.math._

    def apply(numerator: Long, denominator: Long): Rational = {
      val g = gcd(math.abs(denominator), math.abs(numerator))
      val signum = numerator.signum * denominator.signum
      new Rational(signum * math.abs(numerator / g), math.abs(denominator / g))
    }
    def apply(integer: Long): Rational = {
      new Rational(integer, 1)
    }
    def unapply(rational: Rational): Option[(Long, Long)] = {
      Some(rational.numerator, rational.denominator)
    }
    private def gcd(a: Long, b: Long): Long = {
      b match {
        case 0l ⇒ a
        case _ ⇒ gcd(b, a % b)
      }
    }
    class Rational(val numerator: Long, val denominator: Long) {
      def +(that: Rational): Rational = Rational(numerator * that.denominator + denominator * that.numerator, denominator * that.denominator)
      def -(that: Rational): Rational = Rational(numerator * that.denominator - denominator * that.numerator, denominator * that.denominator)
      def *(that: Rational): Rational = Rational(numerator * that.numerator, denominator * that.denominator)
      def /(that: Rational): Rational = Rational(numerator * that.denominator, denominator * that.numerator)
      def +[N](that: N)(implicit convert: ConvertRational[N]): Rational = this + convert.toR(that)
      def -[N](that: N)(implicit convert: ConvertRational[N]): Rational = this - convert.toR(that)
      def *[N](that: N)(implicit convert: ConvertRational[N]): Rational = this * convert.toR(that)
      def /[N](that: N)(implicit convert: ConvertRational[N]): Rational = this / convert.toR(that)
      def <[N](that: N)(implicit convert: ConvertRational[N]): Boolean = RationalNumeric.compare(this, convert.toR(that)) < 0
      def <=[N](that: N)(implicit convert: ConvertRational[N]): Boolean = RationalNumeric.compare(this, convert.toR(that)) <= 0
      def >[N](that: N)(implicit convert: ConvertRational[N]): Boolean = RationalNumeric.compare(this, convert.toR(that)) > 0
      def >=[N](that: N)(implicit convert: ConvertRational[N]): Boolean = RationalNumeric.compare(this, convert.toR(that)) >= 0
      def unary_-(): Rational = Rational(-numerator, denominator)
      override def equals(obj: Any): Boolean = {
        super.equals(obj)
      }
      def equals[N](that: N)(implicit convert: ConvertRational[N]): Boolean = {
        RationalNumeric.compare(this, convert.toR(that)) == 0
      }
      override def toString: String = {
        if (denominator == 1) numerator.toString
        else s"$numerator/$denominator"
      }
    }
    implicit object RationalNumeric extends Fractional[Rational] {
      override def plus(x: Rational, y: Rational): Rational = x + y
      override def minus(x: Rational, y: Rational): Rational = x - y
      override def times(x: Rational, y: Rational): Rational = x * y
      override def negate(x: Rational): Rational = -x
      override def fromInt(x: Int): Rational = Rational(x)
      override def toInt(x: Rational): Int = x.toLong.toInt
      override def toLong(x: Rational): Long = x.numerator / x.denominator
      override def toFloat(x: Rational): Float = x.toDouble().toFloat
      override def toDouble(x: Rational): Double = x.numerator.toDouble / x.denominator
      override def compare(x: Rational, y: Rational): Int = (x - y).numerator.compare(0)
      override def div(x: Rational, y: Rational): Rational = x / y
    }
  }
  implicit class ToRational[N](val value: N)(implicit convert: ConvertRational[N]) {
    def +(that: Rational): Rational = convert.toR(value) + that
    def -(that: Rational): Rational = convert.toR(value) - that
    def *(that: Rational): Rational = convert.toR(value) * that
    def /(that: Rational): Rational = convert.toR(value) / that
  }
  trait ConvertRational[N]{
    def toR(that: N): Rational
  }
  @tailrec
  def gcd(a: Long, b: Long): Long = {
    b match {
      case 0 ⇒ a
      case _ ⇒ gcd(b, a % b)
    }
  }

  implicit class Scope[T](val value: T) extends AnyVal {
    @inline def also(@inline func: T ⇒ Unit): T = {
      func(value)
      value
    }
    @inline def let[A](@inline func: T ⇒ A): A = func(value)
  }
}