切绳子
题目描述
有 N N N 条绳子,它们的长度分别为 L i L_i Li。如果从它们中切割出 K K K 条长度相同的绳子,这 K K K 条绳子每条最长能有多长?答案保留到小数点后 2 2 2 位(直接舍掉 2 2 2 位后的小数)。
输入格式
第一行两个整数 N N N 和 K K K,接下来 N N N 行,描述了每条绳子的长度 L i L_i Li 。
输出格式
切割后每条绳子的最大长度。答案与标准答案误差不超过 0.01 0.01 0.01 或者相对误差不超过 1 % 1\% 1% 即可通过。
样例 #1
样例输入 #1
4 11
8.02
7.43
4.57
5.39
样例输出 #1
2.00
提示
对于 100 % 100\% 100% 的数据 0 < L i ≤ 100000.00 , 0 < n ≤ 10000 , 0 < k ≤ 10000 0<L_i\leq 100000.00,0<n\leq 10000,0<k\leq 10000 0<Li≤100000.00,0<n≤10000,0<k≤10000
代码
#include <iostream>
using std::cin, std::cout;
int n, k; // n 是绳子的条数, k 是切割后绳子的条数
double len[10005]; // len 数组用来存储每条绳子的长度
const double esp = 1e-4; // esp 是精度的限制
bool check(double length) // 判断切割后是否有 k 条绳子的长度为 length
{
int count = 0; // 切割后长度为 length 的绳子的总数
for (int i = 0; i < n; i++)
count += int (len[i] / length); // 抛弃绳子上切割后余下的部分
return (count >= k); // 如果切割后绳子的总数大于等于 k ,则返回真
}
int main()
{
cin >> n >> k; // 读取 n 和 k
double maxlen = 0.0; // 最长的绳子长度
for (int i = 0; i < n; i++)
{
cin >> len[i]; // 读取绳子长度
maxlen = maxlen > len[i] ? maxlen : len[i]; // 将更长的绳长赋值给 maxlen
}
// left 是最小的切割后绳长, right 是最长的切割后绳长, mid 是区间 [left, right] 的中点值
double left = 0.0, right = maxlen, mid;
while (right - left >= esp) // 直到 right - left 小于指定精度才退出循环
{
mid = left + (right - left) / 2; // 防止 right + left 溢出
if (check(mid)) left = mid;
else right = mid;
}
// 以下三行代码用于调整输出两位小数
cout << std::fixed;
cout.precision(2);
cout.setf(std::ios_base::showpoint);
// left 是答案,减去 0.003 是为了修正四舍五入产生的问题
cout << left - 0.003;
return 0;
}