 
  
   
  
   
  
   
  
  def multi_acc[T](n: PolyNum[T], a: PolyNum[T]): PolyNum[T] 
  
  trait PolyNum[T] {
  def +(x:PolyNum[T]) : PolyNum[T]
  def half : PolyNum[T]
  def odd : Boolean
  def one : PolyNum[T]
  def value: T
}
case class X(v:BigInt) extends PolyNum[BigInt] {
  override def +(x:PolyNum[BigInt]) : PolyNum[BigInt] = X(v + x.value)
  override def odd : Boolean = v % 2 == 1
  override def half : PolyNum[BigInt] = X(v / 2)
  override def one : PolyNum[BigInt] = X(BigInt(1))
  override def value: BigInt = v
}
case class Y(v:Int) extends PolyNum[Int] {
  override def +(x:PolyNum[Int]) : PolyNum[Int] = Y(v + x.value)
  override def odd : Boolean = v % 2 == 1
  override def half : PolyNum[Int] = Y(v / 2)
  override def one : PolyNum[Int] = Y(1)
  override def value: Int = v
}
def multi_acc[T](n: PolyNum[T], a: PolyNum[T], r: PolyNum[T]): PolyNum[T] = {
  val odin = n.one
  (n.odd, n) match {
    case (true, odin) => (r + a)
    case (true, _) => multi_acc(n.half, a + a, r + a)
    case (_, _) => multi_acc(n.half, a + a, r)
  }
}
object Main {
  def main(args: Array[String]): Unit = {
    println("привет")
    println(multi_acc(X(BigInt(1)),X(BigInt(3)),X(BigInt(4))).value)
    println(multi_acc(Y(1),Y(3),Y(4)).value)
  }
} 
  
  class Main {
 
  def half(a:Int) : Int = a / 2
  def half(a:BigInt) : BigInt = a / 2
  def odd(a:Int) : Boolean = a % 2 == 1
  def odd(a:BigInt) : Boolean = a % 2 == 1
  def odd[T](a: T): Boolean  =
    a match {
      case x: BigInt => odd(x)
      case x: Int => odd(x)
    }
  def half[T](a: T): T =
    a match {
      case x: Int => half(x).asInstanceOf[T]
      case x: BigInt => half(x).asInstanceOf[T]
    }
  def one[T](n:T): T =
    n match {
      case x: Int => 1.asInstanceOf[T]
      case x: BigInt => BigInt(1).asInstanceOf[T]
    }
  def sum[T](a: T, b:T): T =
    (a, b) match {
      case (x: Int, y: Int) => (x + y).asInstanceOf[T]
      case (x: BigInt, y: BigInt) => (x + y).asInstanceOf[T]
    }
  def mult_acc[T](n: T, a: T, r: T): T = {
    val odin = one(n)
    (odd(n), n) match {
      case (true, odin) => sum(r, a)
      case (true, _) => mult_acc(half(n), sum(a, a), sum(r, a))
      case (_, _) => mult_acc(half(n), sum(a, a), r)
    }
  }
}
object Main {
  def main(args: Array[String]): Unit = {
    println("привет")
    val test = new Main
    println(test.mult_acc(BigInt(1),BigInt(3),BigInt(4)))
    println(test.mult_acc(1,3,4))
  }
} 
  
   
  
   
  
   
  
  