#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const ll M=2e5+5;
ll a[M];  // 存储原始数据(例如:各段绳子的长度)
ll N,K;   // N:原始数据的个数,K:需要满足的目标数量(例如:至少剪出K段绳子)

// 【二分答案的可行性校验函数】
// 功能:判断猜测的答案m是否满足要求(是否能得到至少K个长度为m的片段)
// 返回值:true=满足要求(m可行),false=不满足要求(m不可行)
bool isl(ll m){
    ll cnt=0;  // 统计能分割出的长度为m的片段总数
    for(ll i=1;i<=N;i++){
        // 核心逻辑:单个原始数据a[i]能分割出 floor(a[i]/m) 个长度为m的片段
        // 累加所有数据的可分割片段数,得到总片段数cnt
        cnt+=a[i]/m;
    }
    // 判断总片段数是否满足目标要求(至少K个)
    // 若满足,说明m是一个可行解,尝试寻找更大的可行解;否则m不可行,需要缩小
    if(cnt>=K){
        return true;
    }else return false;
}

int main() {
    // 输入原始数据个数N和目标数量K
    cin>>N>>K;
    // 输入N个原始数据(例如:N段绳子的各自长度)
    for(ll i=1;i<=N;i++){
        scanf("%lld",&a[i]);
    }
    
    // 【二分答案的区间初始化】
    // l:二分左边界,初始为0(最小可能的答案),最终会收敛为"最大可行解"
    // r:二分右边界,初始为1e9+1(一个大于所有可能答案的上界,避免遗漏最优解)
    // 采用「l+1!=r」的二分模板,避免死循环,且最终能精准收敛
    ll l=0,r=1e9+1;
    
    // 【二分答案的核心循环】
    // 循环条件:左边界和右边界不相邻(相邻时说明已收敛,循环终止)
    while(l+1!=r){
        // 计算当前猜测的中间值m(当前待校验的答案)
        // 采用(l+r)/2避免溢出(此处数据范围可直接使用,大数场景可优化为l+(r-l)/2)
        ll m=(l+r)/2;
        
        // 【根据可行性结果调整二分区间】
        if(isl(m)){
            // 情况1:m是可行解(能满足至少K个片段)
            // 目标:寻找"最大的可行解",因此向右探索更大的值,更新左边界为m
            l=m;
        }else{
            // 情况2:m不是可行解(无法满足K个片段)
            // 目标:寻找可行解,因此向左探索更小的值,更新右边界为m
            r=m;
        }
    }
    
    // 【输出结果】
    // 循环终止时,l是最大的可行解(r是第一个不可行解,l即为所求答案)
    cout<<l;
    return 0;
}