Problem:
Score : 500 points

Problem Statement

We have N logs of lengths A_1,A_2,\cdots A_N.

We can cut these logs at most K times in total. When a log of length L is cut at a point whose distance from an end of the log is t (0<t<L), it becomes two logs of lengths t and L-t.

Find the shortest possible length of the longest log after at most K cuts, and print it after rounding up to an integer.

Constraints

1 \leq N \leq 2 \times 10^5

0 \leq K \leq 10^9

1 \leq A_i \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N K
A_1 A_2 \cdots A_N

Output

Print an integer representing the answer.

Sample Input 1

2 3
7 9

Sample Output 1

4

First, we will cut the log of length 7 at a point whose distance from an end of the log is 3.5, resulting in two logs of length 3.5 each.

Next, we will cut the log of length 9 at a point whose distance from an end of the log is 3, resulting in two logs of length 3 and 6.

Lastly, we will cut the log of length 6 at a point whose distance from an end of the log is 3.3, resulting in two logs of length 3.3 and 2.7.

In this case, the longest length of a log will be 3.5, which is the shortest possible result. After rounding up to an integer, the output should be 4.

Sample Input 2

3 0
3 4 5

Sample Output 2

5

Sample Input 3

10 10
158260522 877914575 602436426 24979445 861648772 623690081 433933447 476190629 262703497 211047202

Sample Output 3

292638192

Solution in Rust (1.42.0) (judge verdict: Accepted)

#![allow(unused_imports)]

// language: Rust(1.42.0)
// check available crates on AtCoder at "https://atcoder.jp/contests/language-test-202001"
// My Library Repositry is at "https://github.com/Loptall/sfcpl"

/*
    青perfほしいよ〜！
*/

// from std...
use std::cmp::{
    max, min, Ordering,
    Ordering::{Equal, Greater, Less},
    Reverse,
};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::convert::TryInto;
use std::fmt;
use std::mem::swap;
use std::num::{NonZeroU32, ParseIntError};
use std::ops::{
    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
    Index, IndexMut, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
    SubAssign,
};
use std::process::exit;
use std::{f32, f64, i128, i16, i32, i64, i8, isize, u128, u16, u32, u64, u8, usize};

// Dep' crates are...
use itertools::*;
use itertools_num::*;
use lazy_static::lazy_static;
use maplit::{btreemap, btreeset, hashmap, hashset};
use num_bigint::{BigInt, BigUint};
use num_complex::Complex;
use num_integer::{binomial, gcd, lcm, multinomial, Integer};
use num_rational::Rational;
use num_traits::{
    clamp, one, pow, zero, Num, NumAssignOps, NumOps, One, Pow, Signed, Unsigned, Zero,
};
use permutohedron::Heap;
use proconio::{
    derive_readable, fastout, input, is_stdin_empty,
    marker::{Bytes, Chars, Isize1, Usize1},
};
use rand::random;

pub trait Visualize {
    fn visualize(&self, split: &str);
    fn continuous(&self) {
        self.visualize("");
    }
    fn spaces(&self) {
        self.visualize(" ");
    }
    fn lines(&self) {
        self.visualize("\n");
    }
}
macro_rules! impl_vis_for_sized {
    ($($t:ty),+) => {
        $(
            impl Visualize for $t {
                fn visualize(&self, _split: &str) {
                    print!("{}", self);
                }
            }
        )+
    };
}
impl_vis_for_sized! {
    usize, u8, u16, u32, u64, u128,
    isize, i8, i16, i32, i64, i128,
    f64, f32,
    String, &str, char
}
impl<T: fmt::Display> Visualize for [T] {
    fn visualize(&self, split: &str) {
        print!("{}", self.iter().join(split));
    }
}
#[macro_export]
macro_rules! vis {
    // end
    () => {
        println!();
    };

    // last element + trailing pattern
    ($last:expr ;) => {
        $last.lines();
        vis!()
    };
    ($last:expr =>) => {
        $last.continuous();
        vis!();
    };
    ($last:expr $(,)?) => {
        $last.spaces();
        vis!();
    };

    // get first element and pass rest
    ($first:expr; $($rest:tt)*) => {
        $first.lines();
        println!();
        vis!($($rest)*);
    };
    ($first:expr => $($rest:tt)*) => {
        $first.continuous();
        vis!($($rest)*);
    };
    ($first:expr, $($rest:tt)*) => {
        $first.spaces();
        print!(" ");
        vis!($($rest)*);
    };
}
pub const MOD10E9_7: usize = 1000000007; // 10 ^ 9 + 7
pub const MOD99_: usize = 998244353;
pub const MAX: usize = std::usize::MAX; // = 2 ^ 64 - 1 = 18446744073709551615 ≈ 1.8 * 10 ^ 19
pub const INF: usize = 2000000000000000000; // MAX / 9 < 2 * 10e18 < MAX / 10
pub const FNI: i64 = -2000000000000000000; // == -(INF as i64)
pub const PI: f64 = f64::consts::PI; // 3.141592653589793 -- 10 ^ -15
pub const ASCII_A_LARGE: u8 = 65;
pub const ASCII_A_SMALL: u8 = 97;
pub const ASCII_0: u8 = 48;
pub const ADJ4: &[(isize, isize); 4] = &[(1, 0), (0, 1), (-1, 0), (0, -1)];
pub const ADJ8: &[(isize, isize); 8] = &[
    (1, 0),
    (1, 1),
    (0, 1),
    (-1, 1),
    (-1, 0),
    (-1, -1),
    (0, -1),
    (1, -1),
];

// code...
// #[fastout]
fn main() {
    input! {
        n: usize, k: usize,
        log: [usize; n]
    }

    let l = *log.iter().max().unwrap();
    let ans = binary_search(|x| f(&log, x, k), 1, l + 5).unwrap_or(0) + 1;
    vis!(ans);
}

fn f(log: &Vec<usize>, x: usize, k: usize) -> bool {
    let mut res = 0;
    for &l in log {
        res += (l as f64 / x as f64).ceil() as usize - 1;
    }
    k < res
}

/// # Usage
/// `T`は基本的にusizeが入る想定
/// `pred`について`l`側が`true`、
/// `r`側が`false`を返すような単調性を持っているとき、
/// `pred`を満たす`T`の中で最も大きいものを求める。
/// 最初に`l`と`r`について`pred`がそれぞれ`true`、`false`を返すかどうかを調べるので、
/// 範囲は閉空間で指定して良い。
/// 返り値`res`は必ず、
/// Some(inner) (l <= inner <= r) | None
/// になる
/// ```rust
/// use sfcpl::binary_search::binary_search;
/// let v = vec![1, 3, 3, 3, 4, 6, 7, 7, 8, 10];
/// assert_eq!(3, binary_search(|i| v[i] < 4, 0, v.len() - 1).unwrap());
/// assert_eq!(9, binary_search(|i| v[i] <= 10, 0, v.len() - 1).unwrap());
/// ```
pub fn binary_search<T, F>(pred: F, l: T, r: T) -> Option<T>
where
    T: Add<Output = T> + Div<Output = T> + PartialEq + Copy + From<u8>,
    F: Fn(T) -> bool,
{
    if !pred(l) {
        return None;
    }
    if pred(r) {
        return Some(r);
    }
    let mut l = l;
    let mut r = r;
    let two = T::from(2);
    loop {
        let m = (l + r) / two;
        if l == m {
            break Some(l);
        }
        if pred(m) {
            l = m;
        } else {
            r = m;
        }
    }
}
/// `v`以上の要素が最初に現れるindex
/// ```rust
/// use sfcpl::binary_search::lower_bound;
/// let v: &[i32] = &[1, 3, 3, 4, 5];
/// assert_eq!(lower_bound(v, &0), 0);
/// assert_eq!(lower_bound(v, &1), 0);
/// assert_eq!(lower_bound(v, &2), 1);
/// assert_eq!(lower_bound(v, &3), 1);
/// assert_eq!(lower_bound(v, &4), 3);
/// assert_eq!(lower_bound(v, &5), 4);
/// assert_eq!(lower_bound(v, &999), 5);
/// ```
pub fn lower_bound<T: PartialOrd>(v: &[T], val: &T) -> usize {
    let t = binary_search(|x| v[x] < *val, 0, v.len() - 1);
    match t {
        Some(e) => e + 1,
        None => 0,
    }
}
/// `v`より大きい要素が最初に現れるindex
/// ```rust
/// use sfcpl::binary_search::upper_bound;
/// let v: &[i32] = &[1, 3, 3, 4, 5];
/// assert_eq!(upper_bound(v, &0), 0);
/// assert_eq!(upper_bound(v, &1), 1);
/// assert_eq!(upper_bound(v, &2), 1);
/// assert_eq!(upper_bound(v, &3), 3);
/// assert_eq!(upper_bound(v, &4), 4);
/// assert_eq!(upper_bound(v, &5), 5);
/// assert_eq!(upper_bound(v, &999), 5);
/// ```
pub fn upper_bound<T: PartialOrd>(v: &[T], val: &T) -> usize {
    let t = binary_search(|x| v[x] <= *val, 0, v.len() - 1);
    match t {
        Some(e) => e + 1,
        None => 0,
    }
}