#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;
}