题目描述
有 N 条绳子,它们的长度分别为 Li。如果从它们中切割出 K 条长度相同的绳子,这 K 条绳子每条最长能有多长?答案保留到小数点后 2 位(直接舍掉 2 位后的小数)。
输入格式
第一行两个整数 N 和 K,接下来 N 行,描述了每条绳子的长度 Li。
输出格式
切割后每条绳子的最大长度。答案与标准答案误差不超过 0.01 或者相对误差不超过 1% 即可通过。
输入输出样例
输入 #1
4 11
8.02
7.43
4.57
5.39
输出 #1
2.00
题解
因为和之前的整数二分差不多,我就直接套用了之前自己的代码。
然后就开始疯狂的精度修改,分数在49~93不停乱窜。
但就是不ac。
失败的代码
#include<bits/stdc++.h>
using namespace std;
double a[20000];
double max_duan=0;
int N,K;
int tongji(double mid)
{
int cou=0; //单个记数
for(int j=1;j<=N;j++)
{
cou += floor(a[j]/mid);
if(cou>=K) break;
}
return cou;
}
int main()
{
cin>>N>>K;
for(int i=1;i<=N;i++)
{
cin>>a[i];
if(a[i]>max_duan) max_duan = a[i];
}
double ans=0;
int cou=0;
double low=0.000005,high=max_duan+0.000005;
double mid;
while(low<=high)
{
mid = (low+high)/2; //中间段长
cou = tongji(mid); //精度高对于计算cou有益
if(cou>=K) //?
{
if(tongji(mid+0.000005)>=K)
{
low = mid+0.000005;
ans = mid;
}
else
{
ans = mid;
break;
}
}
else
{
high = mid-0.000005;
}
}
ans *= 100; //去掉后两位的操作
int re = ans;
printf("%.2lf\n",re/100.0);
return 0;
}
最后只能放弃这条路。
我研究了大佬的代码,原来这题可以简化到很简单。
题中说保留小数点后两位(两位之后直接舍弃),又说精度为0.01.
使用double很闹心,根据题中给的条件其实可以回避掉double。
既然小数点后两位有用,那我就把这个数*100. 这样所有有用的部分都进入了整数位,然后存到int数组中。
经过自动类型转换,也就自然舍弃了后面的位。
同时,由于数据扩大了100倍,精度也随之变大,成为了1.
这就变成了之前熟悉的情景了,即整数数据的二分。
这就简单多了。
ac代码
#include<bits/stdc++.h>
using namespace std;
int a[20000];
int max_duan=0;
int N,K;
int tongji(int mid)
{
int cou=0; //单个记数
for(int j=1;j<=N;j++)
{
cou += a[j]/mid;
if(cou>=K) break;
}
return cou;
}
int main()
{
double item;
cin>>N>>K;
for(int i=1;i<=N;i++)
{
cin>>item;
a[i] = item*100;
if(a[i]>max_duan) max_duan = a[i];
}
int ans=0;
int cou=0;
int low=0,high=max_duan+1;
int mid;
while(low<=high)
{
mid = (low+high)/2; //中间段长
if(mid==0) break; //特殊情况
cou = tongji(mid);
if(cou>=K)
{
if(tongji(mid+1)>=K)
{
low = mid+1;
ans = mid;
}
else
{
ans = mid;
break;
}
}
else
{
high = mid-1;
}
}
printf("%.2lf\n",(double)ans/100);
return 0;
}