每日一题(剪绳子)

这道题是找最小值的最大化问题,那么就用二分答案

二分答案的使用条件有两个:

1.有界性(这道题的答案一定在最小绳长和最大绳长之间,满足有界性)

2.单调性(我们切的段数越多,那么这个答案就越小,所以单调递减,满足单调性)

那么我们就从0到最大绳长之间用二分法寻找答案,并依次进行check判断

如果满足条件的话l就=mid(此时的r是最小的满足条件的暂定答案)

如果不满足条件的话就r=mid(说明切的段数少于所需段数,最小值的最大值太大了,那么就缩小边界)

就这样一步步循环,最终找到最小值的最大化

其中一定要注意精度

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int N = 100010;
int n, m;
long long int a[N];
double ans;
bool check(double x)
{
    int cnt = 0;//切的个数
    for (int i = 1; i <= n; i++)//设x是这个答案,那么一共能切cnt段
    {
        cnt += int(a[i] / x);
    }
    return cnt >= m;//条件成立返回ture
}
double bsearch(double l, double r) //注意精度
{
    while (r - l >= 1e-6)//r和l相等时退出循环
    {
        double mid = (l + r) / 2;
        if (check(mid))
            l = mid + 0.0005;
        else
            r = mid - 0.0005;
    }
    return l;
}
int main() {
    cin >> n >> m;
    double l = 0, r = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        r = max(r, a[i] * 1.0);//找边界
    }
    printf("%.2lf", int(bsearch(l, r) * 100) / 100.0);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值