Problem Description
已知有n条绳子,每根绳子至少1米,每条绳子都有一定的长度(单位,米),从中切割出K条长度相同的绳子,求这K条绳子每条最长能有多长?绳子的长度不能小于1厘米,如果不能满足输出 0.00,答案向下保留两位小数(比如1.799999向下保留两位后是1.79 即后面的数字全部舍去)。
1,这里提醒一下,C题要求的是向下保留两位小数,所以不能直接使用%.2f(%.2f是四舍五入到小数点后两位)
Input
输入一行有两个数N,K(1<=N,K<=10000).
第二行有N个数,表示每条绳子的长度(1<=Li<=100000),每个输入都有两位小数.
输入double用%lf,输出用%f,用scanf输入.
Output
输出满足条件的绳子的最长长度(向下保留两位小数).
SampleInput
4 11
8.02
7.43
4.57
5.39
SampleOutput
2.00
这题难点是能不能联想到用二分法去求解。虽然N只有1e4,但是牵扯到小数,如果暴力的话,极有可能是1e41e51e2,血T。所以用二分去遍历所有可能的解,省时间省脑力,二分板子一套,让电脑自己跑去,只不过要根据题意稍作修改。注释才是重点 ,不多BB上代码。
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <math.h>
#include <iostream>
#include <string.h>
const int MAX=1e4+5;
using namespace std;
typedef long long ll;
double len[MAX];
double td(int n, double k)
{
double l=0, r=200000, m; /// 左右界尽量往两边拓,不要太多也不要刚刚好,怕极
///限数据,两边的值没被遍历到
int cnt, i, j;
for (j=0; j<250; j++)/// 因为是小数,不要用while(l<r),直接给它指定多次循环,
{ ///来保证答案的准确性,至于到底来几次,参考2^n >= 1e11
m = (l+r)/2;
cnt = 0; /// 每一次判断都记得要把cnt初始化
for (i=0; i<n; i++)
cnt += (int)(len[i]/m);/// cnt记下临时解m带来的结果,和k去进行比较
/// 这里没有cnt==k的return,和上面j的循环同理,毕竟要求最大解,cnt是向下取整
///的,很可能还没取到最大解,就直接满足条件return了
if (cnt<k)/// 小于说明绳子割长了,把右边界往左缩
r = m;
else /// 大于(等于放哪都一样)说明绳子割短了,再割长点试试
l = m;
}
return r; /// 要最大解,把最终的右边界返回。至于正常的二分查找的返回值,
} ///我再研究研究,搞懂了再去二分法板子那里更新
int main()
{
int N, K, i, j;
cin >> N >> K;
for (i=0; i<N; i++)
scanf ("%lf", &len[i]);
double ans=td(N, K)*100;/// 题目说了不四舍五入,所以我用了土办法,取几位我
ans = (int)ans; ///乘几位,然后向下取整,最后再除回去
ans /= 100;
printf("%.2f", ans); ///这时候不用担心会四舍五入了,小数点后两位后都是0
return 0;
}