import scala.annotation.tailrec
import scala.io.StdIn.{readLong, readLine}

object Main extends App {

  // 1行目 荷物の数 n とトラックの数 k
  val Array(n, k) = readLine().split(" ").map(_.toInt)

  // 2行目以降  n 個の荷物のリスト
  val ws = List.fill(n)(readLong())

  val solver = new Solver(ws, k, n)
  val p      = solver.solve

  println(p)
}

/**
  * この問題専用のソルバ
  * @param packages 荷物の重さのリスト
  * @param trucksNum トラックの台数
  * @param allPackagesNum 荷物の総数(packagesの長さと同じ)
  */
class Solver(packages: List[Long], trucksNum: Int, allPackagesNum: Int) {

  /**
    * メイン計算処理
    * @return すべての荷物を積むために必要な最大積載量 P の最小値
    */
  def solve: Long = {
    import BinarySearch.binarySearch

    // 答えとなりうる値の最小値
    val minL = packages.max
    // 答えとなりうる値の最大値
    val maxR = minL * allPackagesNum

    // 条件を満たす最大積載量 P が最小になるまで二分探索を繰り返す
    binarySearch(minL, maxR)(canLoadBy).get
  }

  /**
    * 引数の最大積載量を設定したときに、すべての荷物を運べるか調べる
    * @param p 最大積載量(全トラックで共通)
    * @return すべての荷物を運ぶことができるならtrue
    */
  def canLoadBy(p: Long): Boolean = {
    import Implicits.ListOps

    // 最大積載量 Pを超えない範囲で荷物を積み込んだ残りの荷物のリストと、
    // 積み込めた荷物の総重量の組を返す関数
    val loadPackages: List[Long] => (Long, List[Long]) = _.reduceWhile { _ + _ }(_ <= p)

    /**
      * すべての荷物を運べるか調べる末尾再帰関数
      * @param restPackages 残りの荷物のリスト
      * @param restTrucksNum 残りのトラック数
      * @return すべての荷物を運ぶことができるならtrue
      */
    @tailrec
    def go(restPackages: List[Long], restTrucksNum: Int): Boolean =
      // すべての荷物を運び終えた
      if (restPackages.isEmpty) true
      // 荷物は残っているが運べるトラックがなくなった
      else if (restTrucksNum == 0) false
      else {
        // 最大積載量 Pを超えない範囲で荷物を積み込んだ残りの荷物のリスト
        val (_, newRestPackages) = loadPackages(restPackages)

        // 情報を反映しループ
        go(newRestPackages, restTrucksNum - 1)
      }

    go(packages, trucksNum)
  }
}

/**
  * 二分探索用オブジェクト
  */
object BinarySearch {

  /**
    * 二分探索
    * @param left  探索範囲左端
    * @param right 探索範囲右端
    * @param p 中間値が探索範囲内かどうかを判定する関数
    * @return 探索範囲内に条件を満たす値があればその最小値。なければNone
    */
  def binarySearch[A](left: A, right: A)(p: A => Boolean)(implicit num: Integral[A]): Option[A] = {
    import num._
    val one = num.one
    val two = num.fromInt(2)

    @tailrec
    def go(l: A, r: A): A =
      if (l >= r) r
      else {
        val mid = (l + r) / two
        if (p(mid))
          go(l, mid)
        else
          go(mid + one, r)
      }

    if (left > right || !p(right))
      None
    else
      Some(go(left, right))
  }
}

/**
  * 拡張メソッド群
  */
object Implicits {

  /**
    * List用拡張メソッド
    * @param self 自身を表すList
    * @tparam A 要素の型
    */
  implicit class ListOps[A](self: List[A]) {

    /**
      * 条件を満たし続ける限りListの要素を集約する
      * 条件を満たさなくなった時点で処理を打切る
      * @param z 初期値
      * @param op 集約演算用の関数
      * @param p 処理を続けるかどうかを判定する述語関数
      * @return 条件を満たさなくなった時点のそれまでの計算結果と残りのリストListの組
      */
    def foldWhile[B](z: B)(op: (B, A) => B)(p: B => Boolean): (B, List[A]) = {

      @tailrec
      def go(zs: List[A], accum: B): (B, List[A]) = zs match {
        case Nil     => (accum, Nil)
        case x :: xs =>
          val s = op(accum, x)
          if (p(s)) go(xs, s) else (accum, zs)
      }

      go(self, z)
    }

    /**
      * foldWhileの初期値を自身の先頭要素にした関数
      */
    def reduceWhile(op: (A, A) => A)(p: A => Boolean): (A, List[A]) =
      self.tail.foldWhile(self.head)(op)(p)
  }
}

