洛谷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

解题思路

首先这题涉及到了intdouble之间的精度转换

所以我们可以把输入的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;
}


posted @ 2020-10-14 18:12  Handwer  阅读(160)  评论(0编辑  收藏  举报