题目描述
我们有 n 条绳子,每条绳子长度为a1, a2, a3 ...an 。我们要将这些绳子切成一模一样的 k 段,要保证每段长度 m(保留两位小数,计算时不考虑四舍五入)最大,输出 m 。
题目思路
-
二分法。1.可行性:当 k 值越大时,m 的值呈单调递减。2.必要性:如果采用暴力拆解法,时间复杂度 O(n*n+n),但用二分法时间复杂度就只有 O(log2(n)*n+n)。在 n 较大时有奇效。(成也暴力拆解法,败也暴力拆解法,会 TLE【Time Limit Exceeded】的痛)
-
因为每一个数都是保留小数点后两位,而且不考虑四舍五入,这明摆着出题人想要我们将这些数据改成整数进行运算。即,将每一个数乘 100,进行整数的二分法运算,在最后除以 100 后输出。
-
注意 small 要小于最小的情况,big 要大于最大的情况。
-
有可能我们将绳子切成 0.01 的长度 m 还是小于 k,这种情况我们无论怎么切绳子都达不到 k 条。即,将每一个元素累加的和 sum 与 k 比较,比 k 小的输出 0.00,并结束程序。
-
尽管 k 不会超出 int,但是我们的 sum 可能会超出 int,需要将 sum 的数据类型定义为 long long。
代码实现
#include<iostream>
using namespace std;
int main(){
int n,k,m=0;cin>>n>>k;int a[n],small=-1,big=0;long long sum=0;
for(int i=0;i<n;i++){
double temp;cin>>temp;a[i]=temp*100;
if(big<a[i])big=a[i];
sum+=a[i];
}
big++;
if(k>sum){cout<<"0.00"<<endl;return 0;}
while(small<big){
int mid=(small+big)/2;m=0;
for(int i=0;i<n;i++)m+=(a[i]/mid);
if(m>=k)small=mid+1;
else big=mid;
}
cout<<(big-1.0)/100<<endl;
return 0;
}
输入输出
样例输入1:
4 11
8.02
7.43
4.57
5.39
输出:
2.00
输入样例2:
1 10000
1.00
输出:
0.00