package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"reflect"
	"sort"
	"strconv"
	"strings"
	// "regexp"
)

/* sort */
type pair struct {
	index  int64
	p1, p2 interface{}
}
type pairs []pair

func (slice pairs) Len() int {
	return len(slice)
}

func (slice pairs) Less(i, j int) bool {
	return slice[i].index < slice[j].index
}

func (slice pairs) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

/* sort */
type Int64Slice []int64

func (slice Int64Slice) Len() int {
	return len(slice)
}

func (slice Int64Slice) Less(i, j int) bool {
	return slice[i] < slice[j]
}

func (slice Int64Slice) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}
func Int64s(a []int64)                    { sort.Sort(Int64Slice(a)) }
func Int64sSliceAreSorted(a []int64) bool { return sort.IsSorted(Int64Slice(a)) }

const (
	initialBufSize = 1e4
	maxBufSize     = 1e8
	INF            = 1e8
)

var (
	scanner = bufio.NewScanner(os.Stdin)
	writer  = bufio.NewWriter(os.Stdout)
	di      = []int64{-1, 0, 1, 0}
	dj      = []int64{0, -1, 0, 1}
	di8     = []int64{-1, -1, 0, 1, 1, 1, 0, -1}
	dj8     = []int64{0, -1, -1, -1, 0, 1, 1, 1}
)

func main() {
	buf := make([]byte, initialBufSize)
	scanner.Buffer(buf, maxBufSize)
	scanner.Split(bufio.ScanWords)
	N, _ := readInt(), readInt()
	S := make([]string, N)
	for i := int64(0); i < N; i++ {
		S[i] = readString()
	}
	sort.Strings(S)
	fmt.Println(strings.Join(S, ""))
}

/*==========================================
 *             Library
 *==========================================*/
func NextPermutation(x sort.Interface) bool {
	n := x.Len() - 1
	if n < 1 {
		return false
	}
	j := n - 1
	for ; !x.Less(j, j+1); j-- {
		if j == 0 {
			return false
		}
	}
	l := n
	for !x.Less(j, l) {
		l--
	}
	x.Swap(j, l)
	for k, l := j+1, n; k < l; {
		x.Swap(k, l)
		k++
		l--
	}
	return true
}
func doubleAry(h int64, w int64, init int64) (res [][]int64) {
	res = make([][]int64, h)
	for i := int64(0); i < h; i++ {
		res[i] = make([]int64, w)
		for j := int64(0); j < w; j++ {
			res[i][j] = init
		}
	}
	return
}

func aryEq(a []int64, b []int64) bool {
	return reflect.DeepEqual(a, b)
}

func clone(n []int64) (r []int64) {
	r = make([]int64, len(n))
	for i := 0; i < len(n); i++ {
		r[i] = n[i]
	}
	return
}
func write(s string) {
	writer.WriteString(s)
}

func print() {
	writer.Flush()
}

// scanner.Split(bufio.ScanWords) をコメントアウトしないと使用不可
func readLine() (s string) {
	if scanner.Scan() {
		s = scanner.Text()
	}
	return s
}

func readInt() (read int64) {
	scanner.Scan()
	read, err := strconv.ParseInt(scanner.Text(), 10, 64)
	if err != nil {
		panic(err)
	}
	return
}

func readFloat() (read float64) {
	scanner.Scan()
	read, err := strconv.ParseFloat(scanner.Text(), 64)
	if err != nil {
		panic(err)
	}
	return
}

func readRunes() (read []rune) {
	scanner.Scan()
	for _, v := range scanner.Text() {
		read = append(read, v)
	}
	return
}

func readString() (read string) {
	scanner.Scan()
	read = scanner.Text()
	return
}

func readStrings() (read []string) {
	scanner.Scan()
	for _, v := range scanner.Text() {
		read = append(read, string(v))
	}
	return
}

func s2i(s string) int64 {
	var intVal, e = strconv.ParseInt(s, 10, 64)
	if e != nil {
		panic(e)
	}
	return intVal
}

func i2s(i int64) string {
	var strVal = strconv.FormatInt(i, 10)
	return strVal
}

func s2f(s string) float64 {
	var floatVal, e = strconv.ParseFloat(s, 64)
	if e != nil {
		panic(e)
	}
	return floatVal
}

func abs(i int64) int64 {
	return int64(math.Abs(float64(i)))
}

func max(a ...int64) int64 {
	ans := int64(0)
	for i, v := range a {
		if i == 0 {
			ans = v
		}
		if ans < v {
			ans = v
		}
	}
	return ans
}
func min(a ...int64) int64 {
	ans := int64(0)
	for i, v := range a {
		if i == 0 {
			ans = v
		}
		if ans > v {
			ans = v
		}
	}
	return ans
}

func sum(i []int64) int64 {
	sum := int64(0)
	for _, val := range i {
		sum += val
	}
	return sum
}

func split(s string) []string {
	return strings.Fields(s)
}

func strAry2intAry(strs []string) []int64 {
	var ret = make([]int64, 0, len(strs))
	for _, str := range strs {
		var intVal = s2i(str)
		ret = append(ret, intVal)
	}
	return ret
}

func intAry2strAry(nums []int64) []string {
	var ret = make([]string, 0, len(nums))
	for _, num := range nums {
		var strVal = i2s(num)
		ret = append(ret, strVal)
	}
	return ret
}

func ary2str(strs []string) string {
	return strings.Join(strs, " ")
}

func reverse(res []int64) []int64 {
	for i, j := 0, len(res)-1; i < j; i, j = i+1, j-1 {
		res[i], res[j] = res[j], res[i]
	}
	return res
}
func reverseStr(res []string) []string {
	for i, j := 0, len(res)-1; i < j; i, j = i+1, j-1 {
		res[i], res[j] = res[j], res[i]
	}
	return res
}

func ini(res []int, init int) {
	if len(res) == 0 {
		return
	}
	res[0] = init
	for i := 0; i < len(res); i++ {
		copy(res[i:], res[:i])
	}
}

//
// func regexpExample() {
//     // Your code here!
//     var str = "13:20"
//     r := regexp.MustCompile(`(\d+):(\d+)`)
//     fmt.Println(r.FindStringSubmatch(str))
// }

// type Country struct {
//     gold int
//     silver int
//     blonze int
// }

// // 複数ソートのサンプル
// func stableSortExample() []Country{
//     var country = []Country {
//         {gold:1, silver:2, blonze:3},
//         {gold:1, silver:2, blonze:3},
//         {gold:1, silver:3, blonze:2},
//         {gold:1, silver:3, blonze:3},
//     }
//     sort.SliceStable(country, func(i, j int) bool { return country[i].blonze > country[j].blonze })
//     sort.SliceStable(country, func(i, j int) bool { return country[i].silver > country[j].silver })
//     sort.SliceStable(country, func(i, j int) bool { return country[i].gold > country[j].gold })
//     return country
// }


package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

const mod = 1000000007

// 1MB
const ioBufferSize = 1 * 1024 * 1024

var sc = func() *bufio.Scanner {
	sc := bufio.NewScanner(os.Stdin)
	sc.Buffer(make([]byte, ioBufferSize), ioBufferSize)
	sc.Split(bufio.ScanWords)
	return sc
}()

func next() string {
	sc.Scan()
	return sc.Text()
}

func nextInt() int {
	sc.Scan()
	i, e := strconv.Atoi(sc.Text())
	if e != nil {
		panic(e)
	}
	return i
}

func main() {
	n, l := nextInt(), nextInt()
	s := make([]string, n)
	res := make([]byte, n*l)

	for i := 0; i < n; i++ {
		s[i] = next()
	}

	sort.Strings(s)

	for i := 0; i < n; i++ {
		for j := 0; j < l; j++ {
			res[i*l+j] = s[i][j]
		}
	}

	fmt.Println(string(res))
}


package main

import (
	"fmt"
	"sort"
)

func main() {
	var n, l int
	fmt.Scan(&n, &l)
	s := make([]string, l)
	for i := 0; i< l; i++{
		fmt.Scan(&s[i])
	}
	sort.Strings(s)

	var ans string
	for _, key := range	 s{
		ans += key
	}
	fmt.Print(ans)
}


package main

import (
	"fmt"
	"sort"
)

func main() {
	var n, l int
	fmt.Scan(&n, &l)
	s := make([]string, l)
	for i := 0; i< l; i++{
		fmt.Scan(&s[i])
	}
	sort.Strings(s)

	var ans string
	for _, key := range s{
		ans += key
	}
	fmt.Println(ans)
}


package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Scan()
	nl := strings.Split(sc.Text(), " ")
	n := strconv.Atoi(nl[0])
	// l, _ := strconv.Atoi(nl[1])

	var s []string
	for i := 0; i < n; i++ {
		sc.Scan()
		s = append(s, sc.Text())
	}

	sort.Strings(s)

	var result string

	for _, str := range s {
		result += str
	}
	fmt.Println(result)
}


fl=gets.chomp.split(" ")
N=fl[0].to_i
L=fl[1].to_i
al=Array.new(N)
0.upto(N-1){|i|
  al[i]=gets.chomp
}
puts al.sort.join('')


N, L = gets.chomp.split(" ").map(&:to_i)
strings = []

N.times do
    strings << gets.chomp
end

strings.sort!
puts strings.join("")


### SNIPPET
  # n = gets.split.map(&:to_i)
  # array = n.times.map { gets.split.map(&:to_i) }
  # [].all?(&:even?)
  # a = [*1..m].repeated_combination(n).to_a
  # [1,2,3,4,5].select { |num| num.even? }  # => [2, 4]
  # ["a","a","b"].group_by(&:itself).map{|k,v| [k, v.count]}.to_h #=> {"a"=>2, "b"=>1}
  # 切り捨て: .floor(2).to_f ,切り上げ： .ceil(2).to_f,四捨五入: round(2)
  # 3.upto(6) do |i|, 6.downto(3) do |i|
  # 公約数125.gcd(100)、公倍数125.lcm(100)
  # PI = Math::PI
  # 高さ = a * Math.sin(w / 180.0 * Math::PI), 底辺 = a * Math.cos(w / 180.0 * Math::PI)
  # def chmax(a, b) a > b ? a : b end
  # INF = Float::INFINITY
  # def chmin(a, b) a < b ? a : b end

n,l = gets.split.map(&:to_i)
s = []
n.times {s << gets.chomp}

puts s.sort.join


n, l = gets.chomp.split(' ').map(&:to_i)
list = []
n.times do
  list << gets.chomp
end
list.sort

print list.join('')


n, l = gets.split
num = n.to_i
len = l.to_i

nums_array = []
num.times {|i|
  alpha_str = gets.chomp
  num_str = ""
  len.times {|c|
    num_str += alpha_str[c].ord.to_s(16)
  }
  nums_array.push(num_str.to_i)
}

result_str = ""
nums_array.sort!
nums_array.each {|val|
  val_str = val.to_s
  0.step(val_str.length - 1, 2) {|i|
    result_str += val_str[i, 2].to_i(16).chr
  }
}
puts result_str


_n, l = gets.split.map(&:to_i)
ary = []
l.times { ary << gets.chomp }

puts ary.sort.join


#![allow(unused, non_snake_case, dead_code, non_upper_case_globals)]
use std::cmp::*;
use std::collections::*;
use std::mem::*;
macro_rules ! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut iter = s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; }
macro_rules ! input_inner { ( $ iter : expr ) => { } ; ( $ iter : expr , ) => { } ; ( $ iter : expr , mut $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let mut $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , mut $ var : ident $ ( $ r : tt ) * ) => { let mut $ var = $ iter . next ( ) . unwrap ( ) . parse ::< usize > ( ) . unwrap ( ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident $ ( $ r : tt ) * ) => { let $ var = $ iter . next ( ) . unwrap ( ) . parse ::< usize > ( ) . unwrap ( ) ; input_inner ! { $ iter $ ( $ r ) * } } ; }
macro_rules ! read_value { ( $ iter : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ iter , $ t ) ) ,* ) } ; ( $ iter : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ iter , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ iter : expr , chars ) => { read_value ! ( $ iter , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ iter : expr , usize1 ) => { read_value ! ( $ iter , usize ) - 1 } ; ( $ iter : expr , $ t : ty ) => { $ iter . next ( ) . unwrap ( ) . parse ::<$ t > ( ) . unwrap ( ) } ; }

fn main() {
    let (r, w, e) = (std::io::stdin(), std::io::stdout(), std::io::stderr());
    let mut io = IO::new(r.lock(), w.lock(), e.lock());
    let (n,l) = (io.read::<usize>(),io.read::<usize>());
    let mut s = (0..n).map(|_| io.read::<String>()).collect::<Vec<String>>();
    s.sort();
    for st in s.iter() {
        io.write(st);
    }
}

static MOD: i64 = 1000000007;
static INF: i64 = std::i64::MAX >> 1;
// IO
use std::io::*;
struct IO<R: Read, W: Write, E: Write> {
    Read: R,
    Write: BufWriter<W>,
    Error: BufWriter<E>,
}
impl<R: Read, W: Write, E: Write> IO<R, W, E> {
    fn new(r: R, w: W, e: E) -> IO<R, W, E> {
        IO {
            Read: r,
            Write: BufWriter::new(w),
            Error: BufWriter::new(e),
        }
    }
    fn read<T>(&mut self) -> T
    where
        T: std::str::FromStr,
    {
        let next: String = self
            .Read
            .by_ref()
            .bytes()
            .map(|c| c.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect();
        next.parse().ok().unwrap()
    }
    fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
    fn readn<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read::<T>()).collect::<Vec<_>>()
    }
    fn readmat<T: std::str::FromStr>(&mut self, n: usize, m: usize) -> Vec<Vec<T>> {
        (0..n).map(|_| self.readn(m)).collect()
    }
    fn write<S: ToString>(&mut self, val: S) {
        self.Write.write(val.to_string().as_bytes());
    }
    fn writeln<S: ToString>(&mut self, val: S) {
        self.Write.write(val.to_string().as_bytes());
        self.Write.write(b"\n");
    }
    fn debug<S: std::fmt::Debug>(&mut self, val: S) {
        writeln!(self.Error, "(debug) {:?}", &val);
    }
    fn debug2<S: std::fmt::Debug, T: std::fmt::Debug>(&mut self, val1: S, val2: T) {
        writeln!(self.Error, "(debug2) {:?} -> {:?}", val1, val2);
    }
    fn debug3<S: std::fmt::Debug, T: std::fmt::Debug, U: std::fmt::Debug>(
        &mut self,
        val1: S,
        val2: T,
        val3: U,
    ) {
        writeln!(
            self.Error,
            "(debug3) {:?} -> {:?} -> {:?}",
            val1, val2, val3
        );
    }
}


fn main() {
    let summary = read_vec::<u32>();
    let words = read_vec2::<String>(*summary.get(0).unwrap());
    let words = quick_sort(&words);
    let mut res = String::new();
    for word in words {
        res = format!("{}{}", res, word);
    }
    println!("{}", res);
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().split_whitespace()
        .map(|e| e.parse().ok().unwrap()).collect()
}

fn read_vec2<T: std::str::FromStr>(n: u32) -> Vec<T> {
    let mut v2 = Vec::new();
    for _ in 0..n {
        let mut s = String::new();
        std::io::stdin().read_line(&mut s).ok();
        let v = s.trim().parse().ok().unwrap();
        v2.push(v);
    }
    v2
}

fn quick_sort(list: &Vec<String>) -> Vec<String> {
    if list.len() == 0 { return Vec::new(); }

    let pivot = list.len() / 2;
    let pivot_val = list.get(pivot).unwrap();

    let mut left : Vec<String> = Vec::new();
    let mut center : Vec<String> = Vec::new();
    let mut right : Vec<String> = Vec::new();

    for val in list {
        if val < pivot_val { left.push(val.to_string()); }
        if val == pivot_val { center.push(val.to_string()); }
        if val > pivot_val { right.push(val.to_string()); }
    }

    let mut sorted = quick_sort(&left);
    sorted.append(&mut center);
    sorted.append(&mut quick_sort(&right));
    sorted
}


macro_rules! input {
     (source = $s:expr, $($r:tt)*) => {
         let mut iter = $s.split_whitespace();
         input_inner!{iter, $($r)*}
     };
     ($($r:tt)*) => {
         let s = {
             use std::io::Read;
         let mut s = String::new();
         std::io::stdin().read_to_string(&mut s).unwrap();
         s
     };
     let mut iter = s.split_whitespace();
     input_inner!{iter, $($r)*}
     };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let mut $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

#[allow(unused_imports)]
use std::cmp::{max, min, Ordering};
#[allow(unused_imports)]
use std::collections::{VecDeque, HashMap, BTreeMap, HashSet, BTreeSet};
#[allow(unused_imports)]
use std::io::{stdout, Write, BufWriter};
//#[allow(unused_imports)]
//use proconio::marker::{Isize1, Usize1, Bytes, Chars};
//#[proconio::fastout]
fn main() {
    input!{
        n: usize,
        _l: usize,
        s: [String; n],
    }
    s.sort();
    let mut ans = String::new();
    for s_ in &s {
        ans += s_;
    };
    println!("{}", ans);
}


use proconio::{fastout, input};
use std::collections::BTreeSet;

#[fastout]
fn main() {
    input! {n: usize, l: usize, s: [String; n]};

    let mut b = BTreeSet::new();

    for i in s.iter() {
        b.insert(i);
    }

    for i in b {
        print!("{}", i)
    }
}


use std::io::Read;

fn main() {
    let mut buf = String::new();

    // 標準入力から全部bufに読み込む
    std::io::stdin().read_to_string(&mut buf).unwrap();

    // 読み込んだStringを空白で分解する
    let mut iter = buf.split_whitespace();
    let _u: usize = iter.next().unwrap().parse().unwrap();
    let q: usize = iter.next().unwrap().parse().unwrap();

    let mut lrt: Vec<String> = (0..q)
        .map(|_| {
                String::from(iter.next().unwrap())
        }).collect();

      lrt.sort();

      let result = lrt.concat();

  	println!("{}", result);

}


use std::io::Read;

fn main() {
    let mut buf = String::new();

    // 標準入力から全部bufに読み込む
    std::io::stdin().read_to_string(&mut buf).unwrap();

    // 読み込んだStringを空白で分解する
    let mut iter = buf.split_whitespace();

    let q: usize = iter.next().unwrap().parse().unwrap();

    let mut lrt: Vec<String> = (0..q)
        .map(|_| {
                String::from(iter.next().unwrap())
        }).collect();

      lrt.sort();

      let result = lrt.concat();

  	println!("{}", result);

}


var _=readLine()!,S=[""];
while let s=readLine(){S+=[s]};
S.sort().forEach{print($0,terminator:"")}


var _=readLine()!,S=[""];while let s=readLine(){S+=[s]};for s in S.sort(){print(s,terminator:"")}


let _=readLine()!,S=(0...99).map{_ in readLine() ?? ""}
S.sort().forEach{print($0,terminator:"")}


import Foundation
let rd = readLine()!.split(separator: " ").map({String($0)}).sorted()
print(rd.joined(separator: ","))


var _=readLine()!,S=[""];while let s=readLine(){S+=[s]};for s in S{print(s,terminator:"")}


let _=readLine()!
var S=[String]()
while let s=readLine() {
    S+=[s!]
}
print(S.sort().joinWithSeparator(""))


import * as fs from 'fs';
const input = fs.readFileSync("/dev/stdin", "utf8").split(/\n/);

// B-文字列大好きいろはちゃんイージー

const N = parseInt(input[0].split(' ')[0]);
const targetText = new Array<string>();
let result = "";

for (let i = 1; i < 1 + N; i++) {
    targetText.push(input[i]);
}

targetText.sort();

targetText.forEach(x => {
    result += x;
});
console.log(result);


import * as fs from 'fs'
const reader = (s: string) => s.split('\n')

function Main(input: string) {
  const [_, ...S] = reader(input)
  console.log(S.sort((a, b) => (a < b ? -1 : 1)).join(''))
}

Main(fs.readFileSync('/dev/stdin', 'utf8'))


function main(input: string) {
  const arrInput: string[] = input
    .split("\n")
    .slice(1)
    .sort();
  console.log(arrInput.join(""));
}

main(require("fs").readFileSync("/dev/stdin", "utf8"));


import * as fs from 'fs';

let input = fs.readFileSync("/dev/stdin", "utf8").split(" ");
input = input.sort();
let s: string = "";
input.forEach(element => {
    s += element;
});
console.log(s);


import * as fs from 'fs';
const input = fs.readFileSync("/dev/stdin", "utf8").split(/\n/);

// B-文字列大好きいろはちゃんイージー

const N = parseInt(input[0].split(' ')[0]);
const targetText = new Array<String>();
let result = '';

for (let i = 1; i < 1 + N; i++) {
    targetText.push(input[i]);
}
console.log(N);
console.log(targetText);

targetText.sort();

targetText.forEach(x => {
    result += x;
});
console.log(result);


import * as fs from 'fs';

const input = fs.readFileSync("/dev/stdin", "utf8").split(/\n/);

const count = parseInt(input[0].split('')[0]);
const target = new Array<string>();
let result = '';

for (let i = 1; i < count + 1; i++) {
    target.push(input[i]);
}

target.sort();

target.forEach(text => {
    result += text;
});

console.log(result);


n,k=[int(i) for i in raw_input().split()]
a=[int(i) for i in raw_input().split()]
s=0
for i in a:
    s+=i
val=(s+n+k-1)/(n+k)
for i in a:
    k-=i/val
if(k>=0):
    print val
else:
    k=abs(k)
    l=[]
    for i in a:
        x=i/val
        if(x>0):
            l.append((i+x-1)/x)
    l.sort()
    print l[k-1]


N, K = map(int, input().split())
logs = list(map(int, input().split()))
maxL = max(logs)

def binsearch(minz, maxz):
    if minz >= maxz:
        return minz

    mid = (maxz + minz)//2
    ncut = 0
    for i in range(N):
        thiscut = int((logs[i] + mid - 1)/mid) - 1
        ncut += thiscut
        if ncut > K:
            return binsearch(mid+1, maxz)

    if ncut < K:
        return binsearch(minz, mid)
    #else ncut == K
    maxx = 0
    for i in range(N):
        thiscut = int((logs[i] + mid - 1)/mid) - 1
        thislen = int((logs[i] + thiscut)/(thiscut+1))
        if maxx < thislen: maxx = thislen
    return maxx

if K > 0:
    ans = binsearch(1, maxL+1)
else:
    ans = maxL
print(ans)


#!/usr/bin/env python3

import os
import sys
import numpy as np

def ncut(l, x):
  return np.sum(np.ceil(l / x) - 1)

def solve(N, K, AS):
  ng, ok = -1, np.amax(AS)
  while abs(ok - ng) > 1:
    mid = (ok + ng) // 2
    if ncut(AS, mid) <= K:
      ok = mid
    else:
      ng = mid

  return ok.item()

def main():
  d = np.fromstring(sys.stdin.read(), dtype=np.int64, sep=' ')
  N, K = d[:2]
  AS = d[2:]

  print('{}'.format(solve(N, K, AS)))

if __name__ == '__main__':
  main()


#from statistics import median
#import collections
#aa = collections.Counter(a) # list to list || .most_common(2)で最大の2個とりだせるお a[0][0]
from math import gcd
from itertools import combinations,permutations,accumulate, product # (string,3) 3回
#from collections import deque
from collections import deque,defaultdict,Counter
import decimal
import re
import math
import bisect
import heapq
#
#
#
# pythonで無理なときは、pypyでやると正解するかも！！
#
#
# my_round_int = lambda x:np.round((x*2 + 1)//2)
# 四捨五入g
#
# インデックス系
# int min_y = max(0, i - 2), max_y = min(h - 1, i + 2);
# int min_x = max(0, j - 2), max_x = min(w - 1, j + 2);
#
#
import sys
sys.setrecursionlimit(10000000)
mod = 10**9 + 7
#mod = 9982443453
#mod = 998244353
INF = float('inf')
from sys import stdin
readline = stdin.readline
def readInts():
  return list(map(int,readline().split()))
def readTuples():
    return tuple(map(int,readline().split()))
def I():
    return int(readline())
n,k = readInts()
A = readInts()
if n == 2:
    print('---')
    exit()
def is_ok(mid):
    cnt = 0
    for i in range(n):
        cnt += (A[i]-1)//mid
        if cnt > k:
            return False
    return True

ok = max(A) + 1
ng = 0
while ok - ng > 1:
    mid = (ok+ng)//2
    if is_ok(mid):
        ok = mid
    else:
        ng = mid

print(ok)


#from statistics import median
#import collections
#aa = collections.Counter(a) # list to list || .most_common(2)で最大の2個とりだせるお a[0][0]
from math import gcd
from itertools import combinations,permutations,accumulate, product # (string,3) 3回
#from collections import deque
from collections import deque,defaultdict,Counter
import decimal
import re
import math
import bisect
import heapq
#
#
#
# pythonで無理なときは、pypyでやると正解するかも！！
#
#
# my_round_int = lambda x:np.round((x*2 + 1)//2)
# 四捨五入g
#
# インデックス系
# int min_y = max(0, i - 2), max_y = min(h - 1, i + 2);
# int min_x = max(0, j - 2), max_x = min(w - 1, j + 2);
#
#
import sys
sys.setrecursionlimit(10000000)
mod = 10**9 + 7
#mod = 9982443453
#mod = 998244353
INF = float('inf')
from sys import stdin
readline = stdin.readline
def readInts():
  return list(map(int,readline().split()))
def readTuples():
    return tuple(map(int,readline().split()))
def I():
    return int(readline())
n,k = readInts()
A = readInts()
if n == 2:
    print('---')
    exit()
def is_ok(mid):
    cnt = 0
    for i in range(n):
        cnt += (A[i]-1)//mid
        if cnt > k:
            return False
    return True

ok = max(A) + 1
ng = -1
while ok - ng > 1:
    mid = (ok+ng)//2
    if is_ok(mid):
        ok = mid
    else:
        ng = mid

print(ok)


import sys
read = sys.stdin.read
readlines = sys.stdin.readlines

from math import ceil
def main():
    n, k = map(int, input().split())
    a = tuple(map(int, input().split()))

    def kaisu(long):
        return(sum([ceil(ae/long) - 1 for ae in a]))

    def bs_meguru(key):
        def isOK(index, key):
            if kaisu(index) <= key:
                return True
            else:
                return False
        ng = 1
        ok = max(a)
        while abs(ok - ng) > 1:
            mid = (ok + ng) // 2
            if isOK(mid, key):
                ok = mid
            else:
                ng = mid
        return ok
    print(bs_meguru(k))

if __name__ == '__main__':
    main()


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author KharYusuf
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "KharYusuf", 1 << 27);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastReader in = new FastReader(inputStream);
            PrintWriter out = new PrintWriter(outputStream);
            ELogs solver = new ELogs();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class ELogs {
        public void solve(int testNumber, FastReader s, PrintWriter w) {
            int n = s.nextInt(), k = s.nextInt();
            int[] a = new int[n];
            for (int i = 0; i < n; i++) a[i] = s.nextInt();
            int l = 1, r = (int) 1e9;
            while (l <= r) {
                int mid = l + r >> 1, req = 0;
                for (int i = 0; i < n; i++)
                    req += (a[i] - 1) / mid;
                if (req <= k) r = mid - 1;
                else l = mid + 1;
            }
            w.println(++r);
        }

    }

    static class FastReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private FastReader.SpaceCharFilter filter;

        public FastReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {

            if (numChars == -1)
                throw new InputMismatchException();

            if (curChar >= numChars) {

                curChar = 0;

                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }

                if (numChars <= 0)
                    return -1;
            }

            return buf[curChar++];
        }

        public int nextInt() {

            int c = read();

            while (isSpaceChar(c))
                c = read();

            int sgn = 1;

            if (c == '-') {
                sgn = -1;
                c = read();
            }

            int res = 0;

            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();

                res *= 10;
                res += c - '0';
                c = read();
            }
            while (!isSpaceChar(c));

            return res * sgn;
        }

        public boolean isSpaceChar(int c) {

            if (filter != null)
                return filter.isSpaceChar(c);

            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


// Utilities
import java.io.*;
import java.util.*;

public class Main {
	static int N, K;
	static int[] a;
	static int l, r, mid;
	static int min = Integer.MAX_VALUE;

	public static void main(String[] args) throws IOException {
		N = in.iscan(); K = in.iscan(); a = new int[N];
		for (int i = 0; i < N; i++) a[i] = in.iscan();
		l = 1; r = (int)1e9;
		while (l <= r) {
			mid = (l+r)/2;
			if (works(mid)) {
				min = mid;
				r = mid-1;
			}
			else {
				l = mid+1;
			}
		}
		out.println(min);
		out.close();
	}

	static boolean works(int x) {
		long cnt = 0;
		long pieces;
		for (int i = 0; i < N; i++) {
			pieces = (a[i] + x - 1) / x;
			cnt += Math.max(0, pieces - 1);
		}
		return cnt <= K;
	}

	static INPUT in = new INPUT(System.in);
	static PrintWriter out = new PrintWriter(System.out);
	private static class INPUT {

		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar, numChars;

		public INPUT (InputStream stream) {
			this.stream = stream;
		}

		public INPUT (String file) throws IOException {
			this.stream = new FileInputStream (file);
		}

		public int cscan () throws IOException {
			if (curChar >= numChars) {
				curChar = 0;
				numChars = stream.read (buf);
			}

			if (numChars == -1)
				return numChars;

			return buf[curChar++];
		}

		public int iscan () throws IOException {
			int c = cscan (), sgn = 1;

			while (space (c))
				c = cscan ();

			if (c == '-') {
				sgn = -1;
				c = cscan ();
			}

			int res = 0;

			do {
				res = (res << 1) + (res << 3);
				res += c - '0';
				c = cscan ();
			}
			while (!space (c));

			return res * sgn;
		}

		public String sscan () throws IOException {
			int c = cscan ();

			while (space (c))
				c = cscan ();

			StringBuilder res = new StringBuilder ();

			do {
				res.appendCodePoint (c);
				c = cscan ();
			}
			while (!space (c));

			return res.toString ();
		}

		public double dscan () throws IOException {
			int c = cscan (), sgn = 1;

			while (space (c))
				c = cscan ();

			if (c == '-') {
				sgn = -1;
				c = cscan ();
			}

			double res = 0;

			while (!space (c) && c != '.') {
				if (c == 'e' || c == 'E')
					return res * UTILITIES.fast_pow (10, iscan ());

				res *= 10;
				res += c - '0';
				c = cscan ();
			}

			if (c == '.') {
				c = cscan ();
				double m = 1;

				while (!space (c)) {
					if (c == 'e' || c == 'E')
						return res * UTILITIES.fast_pow (10, iscan ());

					m /= 10;
					res += (c - '0') * m;
					c = cscan ();
				}
			}

			return res * sgn;
		}

		public long lscan () throws IOException {
			int c = cscan (), sgn = 1;

			while (space (c))
				c = cscan ();

			if (c == '-') {
				sgn = -1;
				c = cscan ();
			}

			long res = 0;

			do {
				res = (res << 1) + (res << 3);
				res += c - '0';
				c = cscan ();
			}
			while (!space (c));

			return res * sgn;
		}

		public boolean space (int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}
	}

	public static class UTILITIES {

		static final double EPS = 10e-6;

		public static int lower_bound (int[] arr, int x) {
			int low = 0, high = arr.length, mid = -1;

			while (low < high) {
				mid = (low + high) / 2;

				if (arr[mid] >= x)
					high = mid;
				else
					low = mid + 1;
			}

			return low;
		}

		public static int upper_bound (int[] arr, int x) {
			int low = 0, high = arr.length, mid = -1;

			while (low < high) {
				mid = (low + high) / 2;

				if (arr[mid] > x)
					high = mid;
				else
					low = mid + 1;
			}

			return low;
		}

		public static int gcd (int a, int b) {
			return b == 0 ? a : gcd (b, a % b);
		}

		public static int lcm (int a, int b) {
			return a * b / gcd (a, b);
		}

		public static long fast_pow_mod (long b, long x, int mod) {
			if (x == 0) return 1;
			if (x == 1) return b;
			if (x % 2 == 0) return fast_pow_mod (b * b % mod, x / 2, mod) % mod;

			return b * fast_pow_mod (b * b % mod, x / 2, mod) % mod;
		}

		public static int fast_pow (int b, int x) {
			if (x == 0) return 1;
			if (x == 1) return b;
			if (x % 2 == 0) return fast_pow (b * b, x / 2);

			return b * fast_pow (b * b, x / 2);
		}

		public static long choose (long n, long k) {
			k = Math.min (k, n - k);
			long val = 1;

			for (int i = 0; i < k; ++i)
				val = val * (n - i) / (i + 1);

			return val;
		}

		public static long permute (int n, int k) {
			if (n < k) return 0;
			long val = 1;

			for (int i = 0; i < k; ++i)
				val = (val * (n - i));

			return val;
		}
	}
}


import java.util.*;
import java.io.*;

public class Main{
    public static boolean pos(int a[],int l,int c){
        int sum=0;
        for(int i=0;i<a.length;i++){
            sum+=a[i];
        }
        if(l==0)return sum<=c;
        int times=0;
        for(int i=0;i<a.length;i++){
            int cut=a[i]/l;
            if(a[i]%l==0)cut--;
            times+=cut;
        }
        return (c>=times);
    }
    public static void main(String []args) throws IOException{
        Reader sc=new Reader();
        PrintWriter out=new PrintWriter(System.out);
        int n=sc.nextInt(),c=sc.nextInt();
        int a[]=new int[n];
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        int hi=Integer.MIN_VALUE,lo=1;
        for(int i=0;i<n;i++){
            hi=Integer.max(hi,a[i]);
        }
        while(hi-lo>1){
            int mid=(hi+lo)/2;
            if(!pos(a,mid,c)){
                lo=mid;
            }else{
                hi=mid;
            }
        }

        if(pos(a,lo,c)){
            out.println(lo);
        }else{
            out.println(hi);
        }
        out.flush();
    }
}

class Reader
    {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[64]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        private byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }


import java.io.*;
import java.util.*;

public class Main {
    public static final long mod = (long)1e9+7;
    public static final long INF = Long.MAX_VALUE/2;
    public static final int inf = Integer.MAX_VALUE/2;

    static void solve(InputReader in, PrintWriter out){
        int n = in.ni(), K = in.ni();
        int[] a = in.ni(n);
        int l = -1, r = inf;
        while(r-l>1){
            int mid = (l+r)/2;
            int k = 0;
            for(int i = 0; i < n; i++) k += (a[i] + mid - 1) / mid-1;
            if(k<=K) r = mid;
            else l = mid;
        }
        out.println(r);
    }

    public static void main(String[] args){
        InputReader in = new InputReader(System.in);
        PrintWriter out = new PrintWriter(System.out);
        solve(in, out);
        out.close();
    }
    public static class InputReader{
        private BufferedReader br;
        private StringTokenizer st;
        public InputReader(InputStream is){
            br = new BufferedReader(new InputStreamReader(is));
            st = null;
        }
        public String ns(){
            if(st == null || !st.hasMoreTokens()){
                try{
                    st = new StringTokenizer(br.readLine());
                }catch (Exception e){
                    throw new RuntimeException(e);
                }
            }
            return st.nextToken();
        }
        public int ni(){
            return Integer.parseInt(ns());
        }
        public long nl(){
            return Long.parseLong(ns());
        }
        public double nd(){
            return Double.parseDouble(ns());
        }
        public char nc(){
            return ns().toCharArray()[0];
        }
        public int[] ni(int n){
            int[] a = new int[n];
            for (int i = 0; i < n; i++) {
                a[i] = ni();
            }
            return a;
        }
        public long[] nl(int n){
            long[] a = new long[n];
            for (int i = 0; i < n; i++) {
                a[i] = nl();
            }
            return a;
        }
        public double[] nd(int n){
            double[] a = new double[n];
            for (int i = 0; i < n; i++) {
                a[i] = nd();
            }
            return a;
        }
    }
}


import java.util.Scanner;

public class Main{
	public static void main(String[] args) {
		try (Scanner sc = new Scanner(System.in);) {
			int n = sc.nextInt();
			int k = sc.nextInt();

			int[] a = new int[n];
			for (int i = 0; i < n; i++) {
				a[i] = sc.nextInt();
			}

			int l = 1;
			int r = 1_000_000_000;
			while (l < r - 1) {
				int mid = (l + r) / 2;

				int cutCount = 0;
				for (int i = 0; i < n; i++) {
					cutCount += (a[i] - 1) / mid;
				}

				if (cutCount <= k) {
					r = mid;
				} else {
					l = mid;
				}
			}

			System.out.println(r);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}


import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.regex.*;
import java.util.stream.*;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

public class Main
{
    public static void main(String[] args)
    {
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        long k=in.nextLong();
        long[] arr=new long[n];
        for(int i=0;i<n;i++)
            arr[i]=in.nextLong();
        long max=Integer.MIN_VALUE;
        for(int i=0;i<n;i++)
            max=Math.max(max,arr[i]);
        long low=1;
        long high=max;
        long curr=max;
        while(low<=high)
        {
            long mid=(low+high)/2;
            long sum=0;
            for(int i=0;i<n;i++)
            {
                if(((arr[i]-mid)%mid)==0)
                    sum+=(arr[i]-mid)/mid;
                else
                    sum+=1+(arr[i]-mid)/mid;
            }
            if(sum<=k)
            {
                high=mid-1;
                curr=mid;
            }
            else
                low=mid+1;
        }
        long sum=0;
        /*for(int i=0;i<n;i++)
        {
            if(((arr[i]-292638192)%292638192)==0)
                sum+=(arr[i]-292638192)/292638192;
            else
                sum+=(1+(arr[i]-292638192)/292638192);
        }*/
        System.out.println(curr);
    }
}


#pragma GCC optimize ("O2")
#pragma GCC target ("avx2")
//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)
#define rep1(i, n) for(int i = 1; i <= (n); i++)
#define co(x) cout << (x) << "\n"
#define cosp(x) cout << (x) << " "
#define ce(x) cerr << (x) << "\n"
#define cesp(x) cerr << (x) << " "
#define pb push_back
#define mp make_pair
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
#define Would
#define you
#define please

const int CM = 1 << 17, CL = 12;
char cn[CM + CL], * ci = cn + CM + CL, * owa = cn + CM, ct;
const ll ma0 = 1157442765409226768;
const ll ma1 = 1085102592571150095;
const ll ma2 = 71777214294589695;
const ll ma3 = 281470681808895;
const ll ma4 = 4294967295;
inline int getint() {
	if (ci - owa > 0) {
		memcpy(cn, owa, CL);
		ci -= CM;
		fread(cn + CL, 1, CM, stdin);
	}
	ll tmp = *(ll*)ci;
	if ((tmp & ma0) ^ ma0) {
		int dig = 68 - __builtin_ctzll((tmp & ma0) ^ ma0);
		tmp = tmp << dig & ma1;
		tmp = tmp * 10 + (tmp >> 8) & ma2;
		tmp = tmp * 100 + (tmp >> 16) & ma3;
		tmp = tmp * 10000 + (tmp >> 32) & ma4;
		ci += (72 - dig >> 3);
	}
	else {
		tmp = tmp & ma1;
		tmp = tmp * 10 + (tmp >> 8) & ma2;
		tmp = tmp * 100 + (tmp >> 16) & ma3;
		tmp = tmp * 10000 + (tmp >> 32) & ma4;
		ci += 8;
		if ((ct = *ci++) >= '0') {
			tmp = tmp * 10 + ct - '0';
			if (*ci++ == '0') {
				tmp = tmp * 10;
				ci++;
			}
		}
	}
	return tmp;
}

int A[200000];
int main() {
	//cin.tie(0);
	//ios::sync_with_stdio(false);

	int N = getint(), K = getint();
	rep(i, N) A[i] = getint() - 1;

	int L = 0, R = 1000000000;
	while (L + 1 < R) {
		int H = (L + R) / 2;
		ll k = 0;
		rep(i, N) k += A[i] / H;
		if (k <= K) R = H;
		else L = H;
	}
	printf("%d\n", R);

	Would you please return 0;
}


//Generated at 2020-08-02 21:36:26 UTC+8
//Created by Alphagocc
#include<bits/stdc++.h>
#ifdef USE_PBDS
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#endif
using namespace std;
#define FI __inline__ __attribute__((always_inline))
#define TN typename
#define TP template
class IO{static const int bufSize=1<<18;char inBuf[bufSize],outBuf[bufSize];char*ip1=inBuf,*ip2=inBuf;int goodReadBit=0,op1=-1,op2=bufSize-1;
TP <TN T>FI void __RI(T&x){int ch=gc(),neg=1;x=0;for(;!(isdigit(ch)||ch=='-'||ch==EOF);ch=gc());if(ch==EOF){goodReadBit=0;return;}if(ch=='-')neg=-1,ch=gc();for(;isdigit(ch);ch=gc())x=x*10+(ch-48)*neg;}
TP <TN T>FI void __RC(T&x){unsigned char ch;while(isspace(ch=gc()));x=ch;}FI void __RS(string&x){char ch;x.clear();for(ch=gc();isspace(ch);ch=gc());if(ch==EOF){goodReadBit=0;return;}for(;!isspace(ch);ch=gc())x.push_back(ch);}
public:
FI int gc(){return ip1==ip2 &&(ip2 =(ip1=inBuf)+fread(inBuf,1,bufSize,stdin),ip1==ip2)?EOF:*ip1++;}
FI IO& R(char&x){__RC(x);return(*this);}FI IO& R(unsigned char&x){__RC(x);return(*this);}FI IO& R(string&x){__RS(x);return(*this);}TP<TN T1,TN T2>FI IO& R(pair<T1,T2>&x){R(x.first),R(x.second);return(*this);}TP<TN T>FI IO& R(vector<T>&x){for(auto &i:x)R(i);return(*this);}
TP <TN T,TN...Args>FI IO& RA(T*a,int n){for(int i=0;i<n;++i)R(a[i]);return(*this);}TP<TN T,TN...Args>FI IO& R(T&x,Args&...args){R(x),R(args...);return(*this);}
TP <TN T,TN...Args>FI IO& RA(T*a,int n,Args...args){for(int i=0;i<n;++i)RA(a[i],args...);return(*this);}TP<TN T>FI IO& R(T&x){static_assert(is_integral<T>::value,"Unsupported types");if(is_integral<T>::value)__RI(x);return(*this);}
private:
char space=' ';TP<TN T>FI void __WI(T x){static char buf[64];static int len=-1;if(x>=0){do{buf[++len]=x%10+48,x/=10;}while(x);}else{pc('-');do{buf[++len]=-(x%10)+48,x/=10;}while(x);}while(len>=0){pc(buf[len]),--len;}}
public:
FI void pc(const char&x){if(op1==op2)flush();outBuf[++op1]=x;}
FI void flush(){fwrite(outBuf,1,op1+1,stdout),op1=-1;}FI IO&W(const char&x){pc(x);return(*this);}FI IO&W(const char*x){while(*x!='\0')pc(*(x++));return(*this);}FI IO&W(const string&x){W(x.c_str());return(*this);}
TP<TN T>FI IO& W(const vector<T>&x){for(auto &i:x)WS(i);WL();return(*this);}FI IO&WL(){W('\n');return(*this);}TP<TN T1,TN T2>FI IO& W(const pair<T1,T2>&x){WS(x.first),W(x.second);return(*this);}
TP<TN T>FI IO& WL(const T&x){W(x),W('\n');return(*this);}FI IO&WS(){W(' ');return(*this);}TP<TN T>FI IO& WS(const T&x){W(x),W(space);return(*this);}
TP<TN T>FI IO& WA(T* a,int n){for(int i=0;i<n;i++)WS(a[i]);WL();return(*this);}TP<TN T,TN...Args>FI IO& W(const T&x,const Args&...args){W(x),W(space),W(args...);return(*this);}
TP<TN...Args>FI IO& WL(const Args&...args){W(args...),W('\n');return(*this);}TP<TN T,TN...Args>FI IO& WA(T* a,int n,Args...args){for(int i=0;i<n;i++)WA(a[i],args...);return(*this);}
TP<TN T>FI IO& W(const T&x){static_assert(is_integral<T>::value,"Unsupported types");if(is_integral<T>::value)__WI(x);return(*this);}
TP<TN T>FI IO&operator>>(T&x){R(x);return(*this);}TP<TN T>FI IO&operator<<(const T&x){W(x);return(*this);}IO(){}}io;
#undef TN
#undef TP
#undef FI
#define REP(i,x,y) for(int i=x;i<y;i++)
#define ALL(x) x.begin(),x.end()
void EXIT(int code){io.flush(),exit(code);}
const int8_t INFC=0x3f;
const int16_t INFS=0x3f3f;
const int32_t INF=0x3f3f3f3f;
const int64_t INFL=0x3f3f3f3f3f3f3f3fLL;

bool check(int x, int k, const vector<int> &a)
{
    int64_t res = 0;
    for (auto i : a) { res += (i - 1) / x; }
    return res <= k;
}
int main()
{
    int n, k;
    io >> n >> k;
    vector<int> a(n);
    io >> a;
    int l = 1, r = 1e9, ans = 0;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (check(mid, k, a)) {
            ans = mid;
            r = mid - 1;
        } else {
            l = mid + 1;
        }
    }
    io.WL(ans);
    EXIT(0);
}


#include<bits/stdc++.h>
using namespace std;
double logs[500000],cut[500000]={0},N,K;
int mins=1000000000;
void f(int x,int y){
	if(x==0 || y>N){
		int maks=0;
		for(int a=1;a<=N;a++){
			if(maks<round(logs[a]/(cut[a]+1)))maks=round(logs[a]/(cut[a]+1));
		}
		if(mins>maks)mins=maks;
	}else{
		for(int a=0;a<=x;a++){
			cut[y]=a;
			f(x-a,y+1);
		}
	}
}

int main(){
	cin>>N>>K;
	for(int a=1;a<=N;a++){
		cin>>logs[a];
	}
	f(K,1);
	cout<<mins<<endl;
}


#include<bits/stdc++.h>
using namespace std;
double logs[500000],cut[500000]={0},N,K;
double mins=1000000000;
void f(int x,int y){
	if(x==0 || y>N){
		double maks=0;
		for(int a=1;a<=N;a++){
			if(maks<logs[a]/(cut[a]+1))maks=logs[a]/(cut[a]+1);
		}
		if(mins>maks)mins=maks;
	}else{
		for(int a=0;a<=x;a++){
			cut[y]=a;
			f(x-a,y+1);
		}
	}
}

int main(){
	cin>>N>>K;
	for(int a=1;a<=N;a++){
		cin>>logs[a];
	}
	f(K,1);
	cout<<round(mins)<<endl;
}


/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author
 */

#include <iostream>
#include <fstream>

#include <iostream>
#include "bits/stdc++.h"

using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef int                     integer;
#define int                     long long
typedef pair<int, int>          pii;
#define vii                     vector<pair<int,int>>
#define vi                      vector<int>
#define vvi                     vector<vector<int>>
#define rep(i, a, b)            for(int i = a; i < (b); i++)
#define s(x)                    in>>x
#define s2(x,y)                 in>>x>>y
#define s3(x,y,z)               in>>x>>y>>z
#define s4(x,y,z,w)             in>>x>>y>>z>>w
#define p(x)                    out<<(x)<<endl
#define p2(x,y)                 out<<(x)<<' '<<(y)<<endl
#define p3(x,y,z)               out<<(x)<<' '<<(y)<<' '<<(z)<<endl
#define p4(x,y,z,w)             out<<(x)<<' '<<(y)<<' '<<(z)<<' '<<(w)<<endl
#define p1d(a,n)                for(int ix=0;ix<n-1;ix++) out<<a[ix]<<' '; out<<a[n-1]<<'\n';
#define p2d(a,n,m)              for(int ix=0;ix<n;ix++){ for(int jx=0;jx<m;jx++) out<<a[ix][jx]<<" "; out<<endl;}
#define pl(x)                   out<<(x)
#define pll(x)                  out<<(x)<<' '
#define range(v)                v.begin(),v.end()
#define all(x)                  begin(x), end(x)
#define sz(x)                   (int)(x).size()
#define rst(x)                  memset(x, -1, sizeof(x))
#define UNVISITED               -1
#define VISITED                 0
#define EXPLORED                2

#define EACH(x, a) for (auto& x: a)
template<class T> void read_v(T& x, std::istream& in) {
    in >> (x);
}
template<class A> void read_vec(vector<A>& x, std::istream& in) {
    EACH(a, x)
        read_v(a, in);
}

ll iceildiv(const ll a, const ll b){ if(a==0){return 0;} return (1 + ((a - 1)/b));}
bool sortpairbysec(const pair<int,int> &a,const pair<int,int> &b){return (a.second < b.second);}
template <typename T>
T factmod(T a, T modulus){ int res = 1, i; for (i = 2; i <= a; i++){ res *= i; res%=modulus;} return res; }
template <typename T>
int powmod(T a, T b, const int m){ int ans=1; while(b>0){if(b&1){ans*=a;ans%=m;}a*=a;a%=m;b>>=1;} return ans; }
template <typename T>
int power(T a, T b){ int ans=1; while(b>0){if(b&1){ans*=a;}a*=a;b>>=1;}return ans;}

bool check(const int target, const vector<int>& a, const int cuts){
    int required = 0;
    for(const int log: a){
        required += (iceildiv(log, target) - 1);
    }
    return (cuts >= required);
}

void ssolve(std::istream& in, std::ostream& out){
    int n, k; s2(n, k);
    vi a(n); read_vec(a, in);
    int l = 0, r = (int)1e9 + 5;
    while(l < r){
        int mid = (l + r)/2;
        if(check(mid, a, k)){
            r = mid;
        }else{
            l = mid + 1;
        }
    }
    p(r);
    return;
}

class ELogs {
public:
void solve(std::istream& in, std::ostream& out) {
    ios_base::sync_with_stdio(false);
    in.tie(nullptr);out.tie(nullptr);
    int t;
    int READ = 0;
    if(READ) s(t);
    else t = 1;
    while(t--){
        ssolve(in, out);
    }
}
};

integer main() {
    ELogs solver;
    std::istream& in(std::cin);
     std::ostream& out(std::cout);
     solver.solve(in, out);
}


#include<stdio.h>
#define MAXN 220000
int a[MAXN],n,k;

int read()
{
	int ans=0,p=1;
	char c = getchar();
	while (c<'0'||c>'9')
	{
		if(c=='-')
			p=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		ans = ans*10+c-'0';
		c=getchar();
	}
	return ans*p;
//	int a;
//	scanf("%d",&a);
//	return a;
}

int solve(int m)
{
	int ans=0;
	for(int i = 1; i <= n; i++)
	{
		ans += a[i]/m;
		if(a[i]%m==0)
			ans--;
		if(ans>k)
			return 0;
	}
	return 1;
}

int main()
{
	n=read(),k=read();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
	}
	int A = 1, B = 2e9;
	while(A < B)
	{
		int mid = (A+B)>>1;
		if(solve(mid) != 1)
		{
			A = mid+1;
		}
		else
		{
			B = mid;
		}
	}
	printf("%d",B);
	return 0;
}


#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#ifdef __cplusplus
#include <bits/stdc++.h>
#endif
//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")

#define getchar getchar_unlocked
#define putchar putchar_unlocked
int32_t nextint(void){ char c=getchar(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar(); bool s=false; if(c=='-'){s=true;c=getchar();} uint32_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar(); } return s?-x:x; }
int64_t nextlong(void){ char c=getchar(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar(); int s=0; if(c=='-'){s=1;c=getchar();} uint64_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar(); } return s?-x:x; }
uint32_t nextstr(char *s){ char c=getchar(); while(c==' '||c=='\n') c=getchar(); uint32_t len=0; while(c!=' '&&c!='\n'){ *s++=c; len++; c=getchar(); } *s='\0'; return len; }
void rsorta_d32(void *base, const int count, const int size, const int index){
	typedef int32_t rsort_t;
	rsort_t (*a)[size] = (rsort_t(*)[size])base;
	rsort_t (*b)[size] = (rsort_t(*)[size])malloc(count*size*sizeof(rsort_t));
	int c[0x100];
	for(int k=0; k<4; k++){
		memset(c, 0, sizeof(c)); for(int i=0; i<count; i++){ c[(a[i][index]>>(k<<3))&0xFF]++; } for(int i=1; i<0x100; i++) c[i]+=c[i-1]; for(int i=count-1; i>=0; i--){ int to=--c[(a[i][index]>>(k<<3))&0xFF]; for(int j=0; j<size; j++){ b[to][j]=a[i][j]; } }{rsort_t(*t)[size]=a; a=b; b=t;}
	}
	free(b);
}

int n;
int a[200000];

inline int f(int k){
	long ans=0;
	for(int i=0; i<n; i++){
		ans+=(a[i]-1)/k;
	}
	return ans>INT_MAX?INT_MAX:ans;
}

int main(void){
	n=nextint();
	int k=nextint();
	for(int i=0; i<n; i++){
		a[i]=nextint();
	}
	int l=1, r=1000000000;
	while(l<=r){
		int m=(l+r)/2;
		if(f(m)<=k) r=m-1; else l=m+1;
	}
	printf("%d\n", l);
}


#include <stdio.h>

int main()
{
	int i, N, K, A[200001], max = 0;
	scanf("%d %d", &N, &K);
	for (i = 1; i <= N; i++) {
		scanf("%d\n", &(A[i]));
		if (A[i] > max) max = A[i];
	}

	int l = 1, r = max, m, tmp, count;
	while (l < r) {
		m = (l + r) / 2;
		for (i = 1, count = 0; i <= N; i++) {
			count += (A[i] - 1) / m;
			if (count > K) break;
		}
		if (count > K) l = m + 1;
		else r = m;
	}

	printf("%d\n", l);
	fflush(stdout);
	return 0;
}


//#include<iostream>
//#include<algorithm>
//#include<queue>
//using namespace std;
//typedef __int128 int;
#define int __int128

int a[200010];

inline int read() {
    char ch = getchar();
    int f = 1;
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -f;
        ch = getchar();
    }
    int x = 0;
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

inline void write(int x) {
    if (x < 0) {
        putchar('-');
        write(-x);
        return;
    }
    if (x < 10) {
        putchar(char(x % 10 + '0'));
        return;
    }
    write(x / 10);
    putchar(char(x % 10 + '0'));
}

int n,k;
int cal(int x){
    int ans=0;
    for(int i=1;i<=n;++i){
        if(a[i]/x>k){
            return 1e9;
        }
        ans=ans+(a[i]/x);
        if(ans>k){
            return 1e9;
        }
    }
    if(ans<0){
        return 1e9;
    }
    return ans;
}

signed main(){
    read(n),read(k);
//    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;++i){
        read(a[i]);
//        scanf("%lld",&a[i]);
    }
    int l=0,r=1e10,mid;
    while(l<=r){
        mid=(l+r)/2;
        int f=cal(mid);
        if(f>k)l=mid+1;
        else r=mid-1;
    }
    write(l);
//    printf("%lld\n",l);

}


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
typedef long long LL;
typedef long double Lf;
#define in (void)scanf
#define Rep(i,a,n)for(int i=(int)(a);i<(int)(n);i++)
//#define Rep(i,a,n)for(LL i=(LL)(a);i<(LL)(n);i++)
#define rep(i,n)Rep(i,0,n)
#define Repp(i,l,r,k)for(int i=(int)(l);i<(int)(r);i+=(int)(k))
//#define Repp(i,l,r,k)for(LL i=(LL)(l);i<(LL)(r);i+=(LL)(k))
#define Ma(x,y) ((x)>(y)?(x):(y))
#define mi(x,y) ((x)<(y)?(x):(y))
#define MOD 4999999999999997//998244353,1000000007,1000000009,4999999999999997
int upi(const void* a, const void* b) { return*(int*)a<*(int*)b ? -1 : *(int*)a> * (int*)b ? 1 : 0; }
int downi(const void* a, const void* b) { return*(int*)a<*(int*)b ? 1 : *(int*)a> * (int*)b ? -1 : 0; }
void sortupi(int* a, int n) { qsort(a, n, sizeof(int), upi); } //1,2,3,4,...
void sortdowni(int* a, int n) { qsort(a, n, sizeof(int), downi); }
int upLL(const void* a, const void* b) { return*(LL*)a<*(LL*)b ? -1 : *(LL*)a> * (LL*)b ? 1 : 0; }
int downLL(const void* a, const void* b) { return*(LL*)a<*(LL*)b ? 1 : *(LL*)a> * (LL*)b ? -1 : 0; }
void sortupLL(LL* a, int n) { qsort(a, n, sizeof(LL), upLL); }
void sortdownLL(LL* a, int n) { qsort(a, n, sizeof(LL), downLL); }
int cmp_char(const void* a, const void* b) { return *(char*)a - *(char*)b; } // a,b,c,d
int cmp_str(const void* a, const void* b) { return strcmp(*(const char**)a, *(const char**)b); } // aaa,aab
LL gcd(LL p, LL q) { while (q) { LL t = p % q; p = q; q = t; }return p; }
LL modpow(LL a,LL n,int m){LL x=1;for(a%=m;n;n/=2)n&1?x=x*a%m:0,a=a*a%m;return x;}
#define invmodpow(b,p)modpow(b,p-2,p)// a/b≡a*b^{-1}(mod p)...return b^{-1}(mod p)
typedef struct fac { LL n, exp; }F;
LL fact(LL n,F*a){LL x=n,i,j,c=0;for(i=2;i*i<=x;i++){for(j=1;x%i==0;j++)x/=i;if(j>1){a[c].n=i;a[c++].exp=j-1;}}if(x-1){a[c].n=x;a[c++].exp=1;}return c;}
LL nibtan(LL* a,LL n,LL x){LL p=0,q=n/2,r=n-1;while(r-p>1){if(x>=a[q])p=q;if(x<=a[q])r=q;q=(p+r)/2;}return a[p]==x?p:r;}
//snippet

#define N 200009

int n, k, a[N];

LL check(int x) {
	LL ret = 0;
	rep(i, n)ret += (LL)ceill((Lf)a[i] / (Lf)x) - 1;
	return ret;
}

void run(void) {
	//saw editorial
	in("%d%d", &n, &k);
	rep(i, n)in("%d", &a[i]);

	int p = 0, q = MOD / 2, r = MOD, ans = n;
	while (r - p > 1) {
		if (check(q) <= (LL)k) r = q;
		else p = q;
		q = (p + r) / 2;
	}
	if (check(r) <= k)ans = r;
	if (check(q) <= k)ans = q;
	if (check(p) <= k)ans = p;
	printf("%d\n", ans ? ans : 1);
}

int main(void) {
	int test = 1;
//	in("%d", &test);
	while (test--) {
		run();
	}
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
typedef long long LL;
typedef long double Lf;
#define in (void)scanf
#define Rep(i,a,n)for(int i=(int)(a);i<(int)(n);i++)
//#define Rep(i,a,n)for(LL i=(LL)(a);i<(LL)(n);i++)
#define rep(i,n)Rep(i,0,n)
#define Repp(i,l,r,k)for(int i=(int)(l);i<(int)(r);i+=(int)(k))
//#define Repp(i,l,r,k)for(LL i=(LL)(l);i<(LL)(r);i+=(LL)(k))
#define Ma(x,y) ((x)>(y)?(x):(y))
#define mi(x,y) ((x)<(y)?(x):(y))
#define MOD 1000000007//998244353,1000000007,1000000009,4999999999999997
int upi(const void* a, const void* b) { return*(int*)a<*(int*)b ? -1 : *(int*)a> * (int*)b ? 1 : 0; }
int downi(const void* a, const void* b) { return*(int*)a<*(int*)b ? 1 : *(int*)a> * (int*)b ? -1 : 0; }
void sortupi(int* a, int n) { qsort(a, n, sizeof(int), upi); } //1,2,3,4,...
void sortdowni(int* a, int n) { qsort(a, n, sizeof(int), downi); }
int upLL(const void* a, const void* b) { return*(LL*)a<*(LL*)b ? -1 : *(LL*)a> * (LL*)b ? 1 : 0; }
int downLL(const void* a, const void* b) { return*(LL*)a<*(LL*)b ? 1 : *(LL*)a> * (LL*)b ? -1 : 0; }
void sortupLL(LL* a, int n) { qsort(a, n, sizeof(LL), upLL); }
void sortdownLL(LL* a, int n) { qsort(a, n, sizeof(LL), downLL); }
int cmp_char(const void* a, const void* b) { return *(char*)a - *(char*)b; } // a,b,c,d
int cmp_str(const void* a, const void* b) { return strcmp(*(const char**)a, *(const char**)b); } // aaa,aab
LL gcd(LL p, LL q) { while (q) { LL t = p % q; p = q; q = t; }return p; }
LL modpow(LL a,LL n,int m){LL x=1;for(a%=m;n;n/=2)n&1?x=x*a%m:0,a=a*a%m;return x;}
#define invmodpow(b,p)modpow(b,p-2,p)// a/b≡a*b^{-1}(mod p)...return b^{-1}(mod p)
typedef struct fac { LL n, exp; }F;
LL fact(LL n,F*a){LL x=n,i,j,c=0;for(i=2;i*i<=x;i++){for(j=1;x%i==0;j++)x/=i;if(j>1){a[c].n=i;a[c++].exp=j-1;}}if(x-1){a[c].n=x;a[c++].exp=1;}return c;}
LL nibtan(LL* a,LL n,LL x){LL p=0,q=n/2,r=n-1;while(r-p>1){if(x>=a[q])p=q;if(x<=a[q])r=q;q=(p+r)/2;}return a[p]==x?p:r;}
//snippet

#define N 100009

int n, k, a[N];

LL check(int x) {
	LL ret = 0;
	rep(i, n)ret += (LL)ceill((Lf)a[i] / (Lf)x) - 1;
	return ret;
}

void run(void) {
	//saw editorial
	in("%d%d", &n, &k);
	rep(i, n)in("%d", &a[i]);

	int p = 0, q = MOD / 2, r = MOD, ans = n;
	while (r - p > 1) {
		if (check(q) <= (LL)k) r = q;
		else p = q;
		q = (p + r) / 2;
	}
	if (check(r) <= k)ans = r;
	if (check(q) <= k)ans = q;
	if (check(p) <= k)ans = p;
	printf("%d\n", ans ? ans : 1);
}

int main(void) {
	int test = 1;
//	in("%d", &test);
	while (test--) {
		run();
	}
	return 0;
}


Main(require("fs").readFileSync("/dev/stdin", "utf8"));

function Main(input) {
  input = input.split("\n");
  const [n, k] = input[0].split(" ").map((a) => parseInt(a, 10));
  const a = input[1].split(" ").map((a) => parseInt(a, 10));
  let l = 0, r = 1e9;
  while (r-l > 1) {
    const x = Math.ceil((l+r)/2);
    let now = 0;
    for(let i=0; i<n; i++) {
      now += Math.ceil((a[i])/x) -1;
    }
    if (now <= k) {
      r = x;
    } else {
      l = x;
    }
  }
  console.log(r);
  return;
}


console.log((args=>{
  const [[N,K],A] = args.trim().split`\n`.map(r=>r.split` `.map(v=>0|v));
  let ng = 0, ok = 1e9;
  while ( ok - ng > 1 ) {
    const m = (ok+ng)>>>1;
    let k = 0;
    for ( let i = 0; i < N; i++ ) {
      k += Math.floor((A[i]-1)/m);
    }
    if ( k > K ) ng = m;
    else ok = m;
  }
  return ok;
})(require('fs').readFileSync('/dev/stdin', 'utf8')));


//Don't have to see. start------------------------------------------
var read = require('readline').createInterface({
  input: process.stdin, output: process.stdout
});
var obj; var inLine = [];
read.on('line', function(input){inLine.push(input);});
read.on('close', function(){
  obj = init(inLine);
  console.error("\n");
  var start = Date.now();
  Main();
  var end = Date.now() - start;
  myerr("time : " + end + "ms");
  myerr("memory : " + Math.round(process.memoryUsage().heapTotal / 1024) + "KB");
});
function makeClone(obj){return JSON.parse(JSON.stringify(obj));}
function nextInt(){return myconv(next(),1);} function nextStrArray(){return myconv(next(),2);}
function nextIntArray(){return myconv(next(),4);} function nextCharArray(){return myconv(next(),6);}
function next(){return obj.next();} function hasNext(){return obj.hasNext();}
function init(input){
  return {
    list : input, index : 0, max : input.length,
    hasNext : function(){return (this.index < this.max);},
    next : function(){if(this.hasNext()){return this.list[this.index++];}else{throw "ArrayIndexOutOfBoundsException ‚There is no more input";}}
  };
}
function myout(s){console.log(s);}
function myerr(s){console.error("debug:" + require("util").inspect(s,false,null));}
//param "no" is
//unknown or outlier : return i. 1: parseInt.
//2: split space. 4: split space and parseInt.
//6: split 1 character. 7: split 1 character and parseInt.
//8: join space. 9: join nextline. 0: join no character.
function myconv(i,no){try{switch(no){case 1:return parseInt(i);case 2:return i.split(" ");case 4:return i.split(" ").map(Number);case 6:return i.split("");case 7:return i.split("").map(Number);case 8:return i.join(" ");case 9:return i.join("\n");case 0:return i.join("");default:return i;}}catch(e){return i;}}

//Don't have to see. end------------------------------------------
function Main(){
  var one = nextIntArray();
  var N = one[0];
  var K = one[1];
  var list = nextIntArray();
  var L = 0;
  var R = 1000000009;
  var output = 0;
  while(Math.abs(R - L) > 1){
    var C = Math.floor((R + L) / 2);
    var count = 0;
    for(var i = 0; i < N; i++){
      count += Math.ceil(list[i] / C) - 1;
    }
    if(count <= K){
      output = C;
      R = C;
    }else{

      L = C;
    }
  }
  myout(output);
}


(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    const lines = input.split(/\n/);
    const [n, k] = lines.shift().split(/\s/).map(v => +v);
    let a = lines[0].split(/\s/).slice(0, n).map(v => [+v, +v, 1]).sort((a, b) => b[1] - a[1]);

    for(let i = 0; i < k; i++){
        let max = a[0];
        max[2]++;
        const divided = max[1] = max[0] / max[2];
        let j = 1;
        while(a[j] && a[j][1] > divided)j++;
        a = a.slice(1, j).concat([max]).concat(a.slice(j, n));
    }
    console.log(Math.ceil(a[0][1]));
})()


(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    const lines = input.split(/\n/);
    const [n, k] = lines.shift().split(/\s/).map(v => +v);
    let a = lines[0].split(/\s/).slice(0, n).map(v => [+v, +v, 1]);

    for(let i = 0; i < k; i++){
        let max = a.reduce((prev, current) => prev[1] > current[1] ? prev : current);
        max[2]++;
        max[1] = max[0] / max[2];
    }
    let max = a.reduce((prev, current) => prev[1] > current[1] ? prev : current);
    console.log(Math.ceil(max[1]));
})()


//解説参照済み

function main(input = "") {
    const lines = input.split("\n");
    const K = 0 | lines[0].split(" ")[1];
    const arr = lines[1].split(" ").map((v) => 0 | v);

    let l = 1;
    let r = Math.max(...arr);
    let mid = 0 | (r + l) * 0.5;
    let res = r;
    while (l <= r) {

        let k = 0;
        arr.forEach((v) => {
            let d = 0 | v / mid;
            if (v === d * mid) { d--; }
            k += d;
        })

        if (k <= K) {
            res = mid;
            r = mid - 1;
        } else {
            l = mid + 1;
        }
        mid = 0 | (r + l) * 0.5;
    }
    return res;
}

//******************************
exports.main = main;

function Main(input) {
    console.log(main(input.trim()));
}

if (process.argv[2] !== "test") {
    Main(require("fs").readFileSync("/dev/stdin", "utf8"));
}


package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
	"strings"
)

const (
	BUFSIZE   = 10000000
	MOD       = 1000000007
	INF_INT   = math.MaxInt32
	INF_INT64 = math.MaxInt64
)

var rdr *bufio.Reader
var N, K int
var A []int

func main() {
	rdr = bufio.NewReaderSize(os.Stdin, BUFSIZE)
	solve()
}

func solve() {
	N, K = readint2()
	A = readIntSlice(N)
	left := 0
	right := int(1e9)
	for abs(right-left) > 1 {
		mid := (left + right) / 2

		if check(mid) {
			right = mid
		} else {
			left = mid
		}
	}
	fmt.Println(right)
}

func check(x int) bool {
	count := 0
	for _, v := range A {
		count += int(math.Ceil(float64(v)/float64(x))) - 1
	}

	return count <= K
}

func readline() string {
	buf := make([]byte, 0, 16)
	for {
		l, p, e := rdr.ReadLine()
		if e != nil {
			fmt.Println(e.Error())
			panic(e)
		}
		buf = append(buf, l...)
		if !p {
			break
		}
	}
	return string(buf)
}

func readIntSlice(size int) []int {
	slice := make([]int, size)
	lines := strings.Split(readline(), " ")
	for i, v := range lines {
		slice[i] = s2i(v)
	}
	return slice
}

func readInt64Slice(size int) []int64 {
	slice := make([]int64, size)
	lines := strings.Split(readline(), " ")
	for i, v := range lines {
		slice[i] = s2i64(v)
	}
	return slice
}

func readint() int {
	return s2i(readline())
}

func readint2() (int, int) {
	lines := strings.Split(readline(), " ")
	return s2i(lines[0]), s2i(lines[1])
}

func readint64() int64 {
	return s2i64(readline())
}

// For int64
func b2i64(b bool) int64 {
	if b {
		return 1
	}
	return 0
}

func abs64(v int64) int64 {
	if v < 0 {
		return -v
	}
	return v
}

func min64(values ...int64) int64 {
	ret := int64(INF_INT64)
	for _, v := range values {
		if ret > v {
			ret = v
		}
	}
	return ret
}

func max64(values ...int64) int64 {
	ret := -int64(INF_INT64)
	for _, v := range values {
		if ret < v {
			ret = v
		}
	}
	return ret
}

func s2i64(s string) int64 {
	v, ok := strconv.ParseInt(s, 10, 64)
	if ok != nil {
		panic("Faild : " + s + " can't convert to int64")
	}
	return v
}

// For int
func b2i(b bool) int {
	if b {
		return 1
	}
	return 0
}

func abs(v int) int {
	if v < 0 {
		return -v
	}
	return v
}

func pow(x, y int) int {
	return int(math.Pow(float64(x), float64(y)))
}

func min(values ...int) int {
	ret := INF_INT
	for _, v := range values {
		if ret > v {
			ret = v
		}
	}
	return ret
}

func max(values ...int) int {
	ret := -INF_INT
	for _, v := range values {
		if ret < v {
			ret = v
		}
	}
	return ret
}

func s2i(s string) int {
	v, ok := strconv.Atoi(s)
	if ok != nil {
		panic("Faild : " + s + " can't convert to int")
	}
	return v
}

func lcm(v1, v2 int) int {
	if v1 > v2 {
		v1, v2 = v2, v1
	}
	for v1 != 0 {
		v1, v2 = v2%v1, v1
	}
	return v2
}

func gcd(v1, v2 int) int {
	return v1 * v2 / lcm(v1, v2)
}

func bit(size int) [][]bool {
	bSize := int(math.Pow(2, float64(size)))
	b := make([][]bool, bSize)
	for i := 0; i < bSize; i++ {
		b[i] = make([]bool, size)
		for j := 0; j < size; j++ {
			if i>>j&1 == 1 {
				b[i][j] = true
			} else {
				b[i][j] = false
			}
		}
	}
	return b
}

/* ------------------------------------------------ */
/* Data stracture                                   */
/* ------------------------------------------------ */
type IntHeap []int

func (h *IntHeap) Push(x interface{}) {
	*h = append(*h, x.(int))
}

func (h *IntHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

func (h IntHeap) Len() int           { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }


package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
)

func main() {
	io := NewIo(os.Stdin, os.Stdout)
	defer io.Flush()
	n, k := io.NextInt(), io.NextInt()
	a := io.NextInts(n)
	ans := solve(n, k, a)
	io.Println(ans)
}

func solve(n, k int, a []int) int {
	divConut := func(x float64) int {
		if x == 0 {
			panic("division by zero")
		}
		cnt := 0
		for i := range a {
			if float64(a[i]) <= x {
				continue
			}
			cnt += int(math.Ceil(float64(a[i])/x)) - 1
		}
		return cnt
	}
	x := sort.Search(maxIter, func(x int) bool { return divConut(float64(x+1)/10) <= k })
	if x == maxIter {
		panic("reached max iteration")
	}
	return int(math.Ceil(float64(x+1) / 10))
}

const maxIter = 1e12

// Io is I/O object
type Io struct {
	reader    *bufio.Reader
	writer    *bufio.Writer
	tokens    []string
	nextToken int
}

// NewIo returns a new Io instance
func NewIo(r io.Reader, w io.Writer) *Io {
	return &Io{
		reader: bufio.NewReader(r),
		writer: bufio.NewWriter(w),
	}
}

// Flush flushes writer
func (io *Io) Flush() {
	err := io.writer.Flush()
	if err != nil {
		panic(err)
	}
}

// NextLine scans a line from stdin
func (io *Io) NextLine() string {
	var buffer []byte
	for {
		line, isPrefix, err := io.reader.ReadLine()
		if err != nil {
			panic(err)
		}
		buffer = append(buffer, line...)
		if !isPrefix {
			break
		}
	}
	return string(buffer)
}

// Next return a word from stdin
func (io *Io) Next() string {
	for io.nextToken >= len(io.tokens) {
		line := io.NextLine()
		io.tokens = strings.Fields(line)
		io.nextToken = 0
	}
	r := io.tokens[io.nextToken]
	io.nextToken++
	return r
}

// NextInt returns an integer from stdin
func (io *Io) NextInt() int {
	i, err := strconv.Atoi(io.Next())
	if err != nil {
		panic(err)
	}
	return i
}

// NextInts returns n integers from stdin
func (io *Io) NextInts(n int) []int {
	ret := make([]int, n)
	for i := 0; i < n; i++ {
		ret[i] = io.NextInt()
	}
	return ret
}

// Println is a wrapper of fmt.Fprintln
func (io *Io) Println(a ...interface{}) {
	fmt.Fprintln(io.writer, a...)
}


package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"math"
	"os"
	"strconv"
)

func main() {
	sc := NewScanner()
	N, K := sc.NextInt(), sc.NextInt()
	A := make([]float64, N)
	for i := 0; i < N; i++ {
		A[i] = sc.NextFloat()
	}

	l := 0.1
	r := 1e9 + 1

	for i := 0; i < 50; i++ {
		c := (r + l) / 2
		a := 0
		for _, v := range A {
			a += int(v / c)
		}
		if a > K {
			l = c
		} else {
			r = c
		}
	}
	fmt.Println(int(math.Ceil(l)))
}

type Scanner struct {
	r   *bufio.Reader
	buf []byte
	p   int
}

func NewScanner() *Scanner {
	rdr := bufio.NewReaderSize(os.Stdin, 1000)
	return &Scanner{r: rdr}
}
func (s *Scanner) Next() string {
	s.pre()
	start := s.p
	for ; s.p < len(s.buf); s.p++ {
		if s.buf[s.p] == ' ' {
			break
		}
	}
	result := string(s.buf[start:s.p])
	s.p++
	return result
}
func (s *Scanner) NextLine() string {
	s.pre()
	start := s.p
	s.p = len(s.buf)
	return string(s.buf[start:])
}
func (s *Scanner) NextInt() int {
	v, _ := strconv.Atoi(s.Next())
	return v
}
func (s *Scanner) NextInt64() int64 {
	v, _ := strconv.ParseInt(s.Next(), 10, 64)
	return v
}

func (s *Scanner) NextFloat() float64 {
	v, _ := strconv.ParseFloat(s.Next(), 64)
	return v
}

func (s *Scanner) NextIntArray() []int {
	s.pre()
	start := s.p
	result := []int{}
	for ; s.p < len(s.buf)+1; s.p++ {
		if s.p == len(s.buf) || s.buf[s.p] == ' ' {
			v, _ := strconv.ParseInt(string(s.buf[start:s.p]), 10, 0)
			result = append(result, int(v))
			start = s.p + 1
		}
	}

	return result
}
func (s *Scanner) NextInt64Array() []int64 {
	s.pre()
	start := s.p
	result := []int64{}
	for ; s.p < len(s.buf)+1; s.p++ {
		if s.p == len(s.buf) || s.buf[s.p] == ' ' {
			v, _ := strconv.ParseInt(string(s.buf[start:s.p]), 10, 64)
			result = append(result, v)
			start = s.p + 1
		}
	}
	return result
}

func (s *Scanner) NextMap() map[int]bool {
	s.pre()
	start := s.p
	mp := map[int]bool{}
	for ; s.p < len(s.buf); s.p++ {
		if s.buf[s.p] == ' ' {
			v, _ := strconv.Atoi(string(s.buf[start:s.p]))
			mp[v] = true
			start = s.p + 1
		}
	}
	v, _ := strconv.Atoi(string(s.buf[start:s.p]))
	mp[v] = true

	return mp
}

func (s *Scanner) pre() {
	if s.p >= len(s.buf) {
		s.readLine()
		s.p = 0
	}
}
func (s *Scanner) readLine() {
	s.buf = make([]byte, 0)
	for {
		l, p, e := s.r.ReadLine()
		if e != nil {
			panic(e)
		}
		s.buf = append(s.buf, l...)
		if !p {
			break
		}
	}
}

// 使い方は下を見ること！！！！！
// https://golang.org/pkg/container/heap/

// An Item is something we manage in a priority queue.
type Item struct {
	value    float64 // stringじゃなくてOK The value of the item; arbitrary.
	priority float64 // マイナスの方が優先  The priority of the item in the queue.
	// The index is needed by update and is maintained by the heap.Interface methods.
	index int // 触らない The index of the item in the heap.
}

// A PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue []*Item

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	// We want Pop to give us the highest, not lowest, priority so we use greater than here.
	return pq[i].priority > pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}

func (pq *PriorityQueue) Push(value interface{}) {
	n := len(*pq)
	item := value.(*Item)
	item.index = n
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	item.index = -1 // for safety
	*pq = old[0 : n-1]
	return item
}

// update modifies the priority and value of an Item in the queue.
func (pq *PriorityQueue) update(item *Item, value float64, priority float64) {
	item.value = value
	item.priority = priority
	heap.Fix(pq, item.index)
}


package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
)

func main() {
	io := NewIo(os.Stdin, os.Stdout)
	defer io.Flush()
	n, k := io.NextInt(), io.NextInt()
	a := io.NextInts(n)
	ans := solve(n, k, a)
	io.Println(ans)
}

func solve(n, k int, a []int) int {
	divConut := func(x float64) int {
		cnt := 0
		for i := range a {
			if float64(a[i]) <= x {
				continue
			}
			cnt += int(math.Ceil(float64(a[i])/x)) - 1
		}
		return cnt
	}
	x := sort.Search(maxIter, func(x int) bool { return divConut(float64(x)/100) <= k })
	if x == maxIter {
		panic("error")
	}
	return int(math.Ceil(float64(x) / 100))
}

const maxIter = 1e12

// Io is I/O object
type Io struct {
	reader    *bufio.Reader
	writer    *bufio.Writer
	tokens    []string
	nextToken int
}

// NewIo returns a new Io instance
func NewIo(r io.Reader, w io.Writer) *Io {
	return &Io{
		reader: bufio.NewReader(r),
		writer: bufio.NewWriter(w),
	}
}

// Flush flushes writer
func (io *Io) Flush() {
	err := io.writer.Flush()
	if err != nil {
		panic(err)
	}
}

// NextLine scans a line from stdin
func (io *Io) NextLine() string {
	var buffer []byte
	for {
		line, isPrefix, err := io.reader.ReadLine()
		if err != nil {
			panic(err)
		}
		buffer = append(buffer, line...)
		if !isPrefix {
			break
		}
	}
	return string(buffer)
}

// Next return a word from stdin
func (io *Io) Next() string {
	for io.nextToken >= len(io.tokens) {
		line := io.NextLine()
		io.tokens = strings.Fields(line)
		io.nextToken = 0
	}
	r := io.tokens[io.nextToken]
	io.nextToken++
	return r
}

// NextInt returns an integer from stdin
func (io *Io) NextInt() int {
	i, err := strconv.Atoi(io.Next())
	if err != nil {
		panic(err)
	}
	return i
}

// NextInts returns n integers from stdin
func (io *Io) NextInts(n int) []int {
	ret := make([]int, n)
	for i := 0; i < n; i++ {
		ret[i] = io.NextInt()
	}
	return ret
}

// Println is a wrapper of fmt.Fprintln
func (io *Io) Println(a ...interface{}) {
	fmt.Fprintln(io.writer, a...)
}


package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
)

func main() {
	io := NewIo(os.Stdin, os.Stdout)
	defer io.Flush()
	n, k := io.NextInt(), io.NextInt()
	a := io.NextInts(n)
	ans := solve(n, k, a)
	io.Println(ans)
}

func solve(n, k int, a []int) int {
	if k == 0 {
		return Max(a...)
	}
	divConut := func(x float64) int {
		cnt := 0
		for i := range a {
			if float64(a[i]) <= x {
				continue
			}
			cnt += int(math.Ceil(float64(a[i])/x)) - 1
		}
		return cnt
	}
	x := sort.Search(maxIter, func(x int) bool { return divConut(float64(x)/10) <= k })
	if x == maxIter {
		panic("error")
	}
	return int(math.Ceil(float64(x) / 10))
}

const maxIter = 1e12

// Max returns max value of inputs
func Max(a ...int) (max int) {
	for i, ai := range a {
		if i == 0 || ai > max {
			max = ai
		}
	}
	return max
}

// Io is I/O object
type Io struct {
	reader    *bufio.Reader
	writer    *bufio.Writer
	tokens    []string
	nextToken int
}

// NewIo returns a new Io instance
func NewIo(r io.Reader, w io.Writer) *Io {
	return &Io{
		reader: bufio.NewReader(r),
		writer: bufio.NewWriter(w),
	}
}

// Flush flushes writer
func (io *Io) Flush() {
	err := io.writer.Flush()
	if err != nil {
		panic(err)
	}
}

// NextLine scans a line from stdin
func (io *Io) NextLine() string {
	var buffer []byte
	for {
		line, isPrefix, err := io.reader.ReadLine()
		if err != nil {
			panic(err)
		}
		buffer = append(buffer, line...)
		if !isPrefix {
			break
		}
	}
	return string(buffer)
}

// Next return a word from stdin
func (io *Io) Next() string {
	for io.nextToken >= len(io.tokens) {
		line := io.NextLine()
		io.tokens = strings.Fields(line)
		io.nextToken = 0
	}
	r := io.tokens[io.nextToken]
	io.nextToken++
	return r
}

// NextInt returns an integer from stdin
func (io *Io) NextInt() int {
	i, err := strconv.Atoi(io.Next())
	if err != nil {
		panic(err)
	}
	return i
}

// NextInts returns n integers from stdin
func (io *Io) NextInts(n int) []int {
	ret := make([]int, n)
	for i := 0; i < n; i++ {
		ret[i] = io.NextInt()
	}
	return ret
}

// Println is a wrapper of fmt.Fprintln
func (io *Io) Println(a ...interface{}) {
	fmt.Fprintln(io.writer, a...)
}


package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
)

func main() {
	io := NewIo(os.Stdin, os.Stdout)
	defer io.Flush()
	n, k := io.NextInt(), io.NextInt()
	a := io.NextInts(n)
	ans := solve(n, k, a)
	io.Println(ans)
}

func solve(n, k int, a []int) int {
	if k == 0 {
		return Max(a...)
	}
	divConut := func(x float64) int {
		cnt := 0
		for i := range a {
			cnt += int(float64(a[i]) / x)
		}
		return cnt
	}
	x := sort.Search(maxIter, func(x int) bool { return divConut(float64(x)/10) <= k })
	if x == maxIter {
		panic("error")
	}
	return int(math.Ceil(float64(x) / 10))
}

const maxIter = 1e12

// Io is I/O object
type Io struct {
	reader    *bufio.Reader
	writer    *bufio.Writer
	tokens    []string
	nextToken int
}

// NewIo returns a new Io instance
func NewIo(r io.Reader, w io.Writer) *Io {
	return &Io{
		reader: bufio.NewReader(r),
		writer: bufio.NewWriter(w),
	}
}

// Flush flushes writer
func (io *Io) Flush() {
	err := io.writer.Flush()
	if err != nil {
		panic(err)
	}
}

// NextLine scans a line from stdin
func (io *Io) NextLine() string {
	var buffer []byte
	for {
		line, isPrefix, err := io.reader.ReadLine()
		if err != nil {
			panic(err)
		}
		buffer = append(buffer, line...)
		if !isPrefix {
			break
		}
	}
	return string(buffer)
}

// Next return a word from stdin
func (io *Io) Next() string {
	for io.nextToken >= len(io.tokens) {
		line := io.NextLine()
		io.tokens = strings.Fields(line)
		io.nextToken = 0
	}
	r := io.tokens[io.nextToken]
	io.nextToken++
	return r
}

// NextInt returns an integer from stdin
func (io *Io) NextInt() int {
	i, err := strconv.Atoi(io.Next())
	if err != nil {
		panic(err)
	}
	return i
}

// NextInts returns n integers from stdin
func (io *Io) NextInts(n int) []int {
	ret := make([]int, n)
	for i := 0; i < n; i++ {
		ret[i] = io.NextInt()
	}
	return ret
}

// Println is a wrapper of fmt.Fprintln
func (io *Io) Println(a ...interface{}) {
	fmt.Fprintln(io.writer, a...)
}

// Max returns max value of inputs
func Max(a ...int) (max int) {
	for i, ai := range a {
		if i == 0 || ai > max {
			max = ai
		}
	}
	return max
}


N, K = gets.chomp.split.map(&:to_i)
AS = gets.chomp.split.map(&:to_i)

as_sum = AS.sum
num = N + K
num_cut_float = AS.map { |a| 1.0 * num * a / as_sum }
                  .map { |a| a < 1 ? 1 : a}
num_cut_int = num_cut_float.map(&:to_i)

as_length = []
AS.size.times do |i|
  as_length << (1.0 * AS[i] / num_cut_int[i]).ceil
end
as_length = as_length.sort.reverse
puts as_length[N + K - num_cut_int.sum]


# 入力：N本ある丸太を合計K回切ることができる
N, K = gets.chomp.split.map(&:to_i)

# 入力：N本ある丸太それぞれの長さ
A = gets.chomp.split.map(&:to_i)

# 長さ候補rangeのそれぞれについて、k回で切れるか二分探索
ans = (1 .. A.max).bsearch{|x| A.sum{(_1 - 1) / x} <= K}

# 出力
puts ans


n,k=gets.split.map &:to_i
a=gets.split.map &:to_i
p (1..a.max).bsearch{|x|a.sum{(_1-1)/x}<=k}


# after YouTube editorial
n,k = gets.strip.split.map(&:to_i)
a = gets.strip.split.map(&:to_i)
l = 1
r = a.max
while r - l > 1
  x = (l+r)/2
  y = 0
  a.each do |e|
    y += (e+x-1)/x-1 if e > x
  end
  if y > k
    l = x
  else
    r = x
  end
end
p r


N,K = gets.split.map &:to_i
A = gets.split.map &:to_i

p (1..10**9).bsearch{|l| A.inject(0){|total,a| total+(a.to_r/l).ceil - 1} <= K }


# 入力：N本ある丸太を合計K回切ることができる
N, K = gets.chomp.split.map(&:to_i)

# 入力：N本ある丸太それぞれの長さ
A = gets.chomp.split.map(&:to_i)

# 切り終えたとき最大の丸太の長さの候補
range = [1..A.max]

# 長さ候補rangeのそれぞれについて、k回で切れるか二分探索
ans = range.bsearch{|x| A.sum{(_1 - 1) / x} <= K}

# 出力
puts ans


#![allow(unused_imports)]
#![allow(non_snake_case)]
use proconio::{input, fastout};
use proconio::marker::{Chars, Bytes, Usize1};

#[fastout]
fn main() {
    input!{
        n: usize, k:u32,
        c: [u32; n]
    }
    let mut ng = 0;
    let mut ok = *c.iter().max().unwrap() + 1;
    while ok - ng > 1 {
        let mid = (ok + ng) / 2;
        let mut cnt = 0;
        for &x in &c {
            cnt += (x - 1) / mid;
        }
        if cnt <= k {
            ok = mid
        } else {
            ng = mid
        }
    }
    println!("{}", ok);
}


#![allow(unused_imports)]
#![allow(dead_code)]

use proconio::input;
use proconio::marker::{Bytes, Chars};
use std::collections::*;

fn main() {
    input! {
        n:usize,
        k:i32,
        a:[i32;n],
    }
    let mut ok = *a.iter().max().unwrap();
    let mut no = 0;
    while (ok - no).abs() > 1 {
        let mid = (ok + no) / 2;
        let ope_num = a
            .iter()
            .fold(0, |acc, &len| acc + (len + mid - 1) / mid - 1);
        if ope_num <= k {
            ok = mid;
        } else {
            no = mid;
        }
    }
    println!("{}", ok);
}


#![allow(unused_imports, unused_macros)]

use kyoproio::*;
use std::{
    collections::*,
    io::{self, prelude::*},
    iter,
    mem::{replace, swap},
};

fn main() -> io::Result<()> {
    std::thread::Builder::new()
        .stack_size(64 * 1024 * 1024)
        .spawn(|| {
            let stdin = io::stdin();
            let stdout = io::stdout();
            run(KInput::new(stdin.lock()), io::BufWriter::new(stdout.lock()))
        })?
        .join()
        .unwrap()
}

fn run<I: Input, O: Write>(mut kin: I, mut out: O) -> io::Result<()> {
    macro_rules! output { ($($args:expr),+) => { write!(&mut out, $($args),+)?; }; }
    macro_rules! outputln {
        ($($args:expr),+) => { output!($($args),+); outputln!(); };
        () => { output!("\n"); if cfg!(debug_assertions) { out.flush()?; } }
    }

    let (n, k): (usize, i32) = kin.input();
    let a: Vec<i32> = kin.seq(n);

    let mut l = 0;
    let mut r = 1e9 as i32;

    while r - l >= 2 {
        let m = (l + r) / 2;
        let mut s = 0;
        for &x in a.iter() {
            s += (x + m - 1) / m - 1;
        }
        if s <= k {
            r = m;
        } else {
            l = m;
        }
    }
    outputln!("{}", r);

    Ok(())
}

// -----------------------------------------------------------------------------
pub mod kyoproio {
    use std::io::prelude::*;
    pub trait Input {
        fn str(&mut self) -> &str;
        fn input<T: InputParse>(&mut self) -> T {
            T::input(self)
        }
        fn iter<T: InputParse>(&mut self) -> Iter<T, Self> {
            Iter(self, std::marker::PhantomData)
        }
        fn seq<T: InputParse, B: std::iter::FromIterator<T>>(&mut self, n: usize) -> B {
            self.iter().take(n).collect()
        }
    }
    pub struct KInput<R> {
        src: R,
        buf: String,
        pos: usize,
    }
    impl<R: BufRead> KInput<R> {
        pub fn new(src: R) -> Self {
            Self {
                src,
                buf: String::with_capacity(1024),
                pos: 0,
            }
        }
    }
    impl<R: BufRead> Input for KInput<R> {
        fn str(&mut self) -> &str {
            loop {
                if self.pos >= self.buf.len() {
                    self.pos = 0;
                    self.buf.clear();
                    if self.src.read_line(&mut self.buf).expect("io error") == 0 {
                        return &self.buf;
                    }
                }
                let range = self.pos
                    ..self.buf[self.pos..]
                        .find(|c: char| c.is_ascii_whitespace())
                        .map(|i| i + self.pos)
                        .unwrap_or_else(|| self.buf.len());
                self.pos = range.end + 1;
                if range.end > range.start {
                    return &self.buf[range];
                }
            }
        }
    }
    pub struct Iter<'a, T, I: ?Sized>(&'a mut I, std::marker::PhantomData<*const T>);
    impl<'a, T: InputParse, I: Input + ?Sized> Iterator for Iter<'a, T, I> {
        type Item = T;
        fn next(&mut self) -> Option<T> {
            Some(self.0.input())
        }
    }
    pub trait InputParse: Sized {
        fn input<I: Input + ?Sized>(src: &mut I) -> Self;
    }
    impl InputParse for Vec<u8> {
        fn input<I: Input + ?Sized>(src: &mut I) -> Self {
            src.str().as_bytes().to_owned()
        }
    }
    macro_rules! from_str_impl {
        { $($T:ty)* } => {
            $(impl InputParse for $T {
                fn input<I: Input + ?Sized>(src: &mut I) -> Self {
                    src.str().parse::<$T>().expect("parse error")
                }
            })*
        }
    }
    from_str_impl! {
        String char bool f32 f64 isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128
    }
    macro_rules! tuple_impl {
        ($H:ident $($T:ident)*) => {
            impl<$H: InputParse, $($T: InputParse),*> InputParse for ($H, $($T),*) {
                fn input<I: Input + ?Sized>(src: &mut I) -> Self {
                    ($H::input(src), $($T::input(src)),*)
                }
            }
            tuple_impl!($($T)*);
        };
        () => {}
    }
    tuple_impl!(A B C D E F G);
    #[macro_export]
    macro_rules! kdbg {
        ($($v:expr),*) => {
            if cfg!(debug_assertions) { dbg!($($v),*) } else { ($($v),*) }
        }
    }
}


// -*- coding:utf-8-unix -*-

#[macro_use]
extern crate lazy_static;
extern crate num_bigint; // 0.2.2
extern crate num_traits; // 0.2.8
use num_bigint::BigInt;
use num_bigint::ToBigInt;
use num_traits::abs;
use num_traits::Pow;
use num_traits::{One, Zero};

// use proconio::derive_readable;
use proconio::fastout;
use proconio::input;
// use std::convert::TryInto;
// use ascii::Chars;
use proconio::marker::{Bytes, Chars};
use std::cmp::*;
use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque};
use std::io::*;
use std::ops::Range;
use std::str::FromStr;
use superslice::*;

use lazy_static::lazy_static;
use std::sync::Mutex;

pub fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

lazy_static! {
    // static ref PARENTS: Mutex<Vec<usize>> = Mutex::default();
    // static ref CHILDS: Mutex<Vec<Vec<usize>>> = Mutex::default();
    static ref ADJ: Mutex<Vec<Vec<usize>>> = Mutex::default();
}

// const MOD: usize = 9997063;
// const MOD: usize = 100_000_000_ + 7;

//tenka1-2019-C
// #[fastout]
fn main() {
    input![n: usize, k: usize, a: [usize; n]];

    let mut ng = -1;
    let mut ok = *a.iter().max().unwrap() as i64;

    /* ok と ng のどちらが大きいかわからないことを考慮 */
    while abs(ok - ng) > 1 {
        let mid = (ok + ng) / 2;

        if is_ok(mid, k, &a) {
            ok = mid;
        } else {
            ng = mid;
        }
    }

    // return ok;

    println!("{}", ok);
}

fn is_ok(v: i64, k: usize, a: &Vec<usize>) -> bool {
    return a.iter().map(|a| *a as i64 / v).sum::<i64>() <= k as i64;
}

// let mut values = VALUES.lock().unwrap();
// values.extend_from_slice(&[1, 2, 3, 4]);
// assert_eq!(&*values, &[1, 2, 3, 4]);

// -100000000
//  1000000000


use proconio::{fastout, input};

#[fastout]
fn main() {
    input! {
        n: usize,
        k:usize,
        mut a:[usize;n],
    }
    a.sort();

    let mut l = 1;
    let mut r = a[n-1];

    while l+1 < r{
        let mid = (l+r)/2;

        let mut tmp : u128 = 0;
        for e in &a{
            if *e%mid == 0{
                tmp += (*e/mid -1) as u128;
            }else{
                tmp += (*e/mid) as u128;
            }
        }

        if tmp > k as u128{
            l = mid;
        }else{
            r = mid;
        }
    }
    println!("{}",r);
}


use proconio::{fastout, input};

#[fastout]
fn main() {
    input! {
        n: usize,
        k:usize,
        mut a:[usize;n],
    }
    a.sort();

    let mut l = 1;
    let mut r = 1_000_000_100;

    while l+1 < r{
        let mid = (l+r)/2;

        let mut tmp = 0;
        for e in &a{
            if *e%mid == 0{
                tmp += *e/mid -1;
            }else{
                tmp += *e/mid;
            }
        }

        if tmp > k{
            l = mid;
        }else{
            r = mid;
        }
    }
    println!("{}",r);
}