题目描述
有 N 根绳子,第 i 根绳子长度为 Li,现在需要 M 根等长的绳子,你可以对NN 根绳子进行任意裁剪(不能拼接),请你帮忙计算出这 M 根绳子最长的长度是多少。
输入格式
第一行包含 2 个正整数 N, M,表示原始绳子的数量和需求绳子的数量。
第二行包含 N个整数,其中第 i 个整数 Li 表示第 i 根绳子的长度。
输出格式
输出一个数字,表示裁剪后最长的长度,保留两位小数。
样例
输入数据 1
3 4
3 5 4
输出数据 1
2.50
数据范围
1≤N,M≤100000
0<Li<10的9次方
题解:
用二分法
先求出绳子中最长的一根并与其二分
利用二分法先求中间值,如果用中间值截取的绳长度个数小于m,则中间值较大,将右边的最大值设为中间值,然后继续取最小值和最大值的中间值,如果用中间值截取的绳长度个数大于m,则中间值较小,将左边的最小值设为中间值,然后继续取最小值和最大值的中间值。这样反复取值,最小和最大值将无限靠近正确答案,因为所要求的精度为0.01,可能会出现四舍五入,则要往后精确两位,则为0.0001。
#include<bits/stdc++.h>
using namespace std;
int n,m,maxx,ans;
int l[1000001];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&l[i]);
maxx=max(l[i],maxx);//找到最大值
}
double z=0,y=maxx;
while(y-z>0.0001){//两者差距至四位小数点则结束循环
ans=0;//每次循环从ans都从0开始计算
double zj=(z+y)/2;//取两者中间值
for(int i=1;i<=n;i++){
ans=ans+l[i]/zj;//计算每根绳截取长度能满足中间值并相加
}
if(ans<m){//不满足则截取长度过大往左边移动
y=zj;
}
if(ans>=m){//满足则截取长度过小或刚刚好,则往右移动
z=zj;
}
}
printf("%.2lf",z);
return 0;
}