洛谷P1577《切绳子》
原更新日期:2018-10-31 20:31:05
突然想起《割绳子》
题面描述
有N条绳子,它们的长度分别为Li。如果从它们中切割出K条长度相同的绳子,这K条绳子每条最长能有多长?答案保留到小数点后2位。
Input / Output 格式 & 样例
输入格式
第一行两个整数N和K,接下来N行,描述了每条绳子的长度Li。
输出格式
切割后每条绳子的最大长度。
输入样例
4 11
8.02
7.43
4.57
5.39
输出样例
2.00
解题思路
首先这题涉及到了int
和double
之间的精度转换
所以我们可以把输入的double
都乘100转为int
(题目要求保留两位小数)
不难看出来这题可以枚举答案 但是显然会炸
于是我们要想点优化——二分答案!
我们选择二分绳子的最大长度
这题的单调性是显然的,我就不证了(
Check(int mid)
怎么写?
我们扫一遍绳子长度L[]
,令$ ans=\sum_{i=1}^{n}\lfloor\frac{L[i]}{mid}\rfloor $
即最终绳子被分成的段数
如果\(ans \geq k\)(题目中的\(\text{k}\))则把左边界赋值为mid + 1
,否则把右边界赋值为mid - 1
这里要注意的是如果mid == 0
就直接退出循环
最后cout << fixed << setprecision(2) << (double) r / 100.0 << endl;
代码实现
#include <iostream>
#include <cstdio>
#include <cstring>
#include <iomanip>
using namespace std;
const int MAXN = 10000 + 10;
const double MAXL = 100000.00;
int n, k;
int L[MAXN];
bool Check(int x) {
int ans = 0;
for (int i = 1; i <= n; ++i) ans += L[i] / x;
return ans >= k;
}
int main(int argc, char *const argv[]) {
ios::sync_with_stdio(false);
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
double P;
cin >> P;
L[i] = (int) (P * 100.0);
}
int l = 0, r = 19260817 + 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (mid == 0) break;
if (Check(mid)) l = mid + 1;
else r = mid - 1;
}
cout << fixed << setprecision(2) << (double) r / 100.0 << endl;
return 0;
}