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 Java (OpenJDK 11.0.6) (judge verdict: Accepted)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.PriorityQueue;
import java.util.Scanner;

class Main {
    static final int MOD = 1000000007;
    static final int INF = 1 << 30;
    static final int ALF = 26;

    ArrayList<Wood> list = new ArrayList<Wood>();
    int K;
    int N;
    Main() {
        Scanner sc = new Scanner(System.in);
        long ans = 0;
        N = sc.nextInt();
        K = sc.nextInt();

        // PriorityQueue<Wood> queue = new
        // PriorityQueue<Wood>(Comparator.comparing(Wood::LEND));
        for (int i = 0; i < N; i++) {
            Wood w = new Wood(sc.nextInt());
            list.add(w);
            // queue.add(w);
        }
        /*
         * int cut = 0; while(true){ int remain = K-cut; Wood w = queue.poll();
         * if(w.COST() <= remain){ w.CUT(); queue.add(w); }else{ ans =
         * (long)Math.floor(w.LEND()); break; } }
         */

        ans = binarySearch(1, 1000000001);

        System.out.println(ans);
    }

    int binarySearch(int min, int max) {
        int ng = min - 1, ok = max;
        while (ok - ng > 1) {
            int mid = ng + (ok - ng) / 2;
            if (isOK(mid))
                ok = mid;
            else
                ng = mid;
        }
        if (ok == max)
            throw new Error("all false");
        return ok;
    }

    boolean isOK(int key) {
        long sum = 0;
        for (int i = 0; i < N; i++) {
            Wood w = list.get(i);
            if (w.length <= key)
                continue;
            //double col = (double)w.length / key;
            //sum += (w.length / key) - (((w.length % key) == 0) ? 1 : 0);
            int ck = (w.length / key);
            if((double)w.length/ck > key){
                //ck++;
            }else{
                ck--;
            }
            sum += ck;
            if (sum > K){
                //System.err.println(key+" is false " + sum);
                return false;
            }
        }
        //System.err.println(key+" is true "+sum);
        return true;
    }

    public static void main(String[] args) {
        new Main();
    }

    class Wood {
        int length;
        int cut;

        Wood(int length) {
            this.length = length;
            cut = 0;
        }

        void CUT() {
            cut += cut + 1;
        }

        int COST() {
            return cut + 1;
        }

        int LEN() {
            return length / (cut + 1);
        }

        double LEND() {
            return length / (cut + 1d);
        }
    }
}