(Kattis - fence2)G - Building Fences(二分法)(补)

Donald is a fence builder. He wants to build a fence that is N−1N−1 meters long. He needs a fence post every meter along the fence, which means he needs NN fence posts. Donald has KK poles of varying lengths that he wants to use as fence posts. The fence posts must have the same lengths, and be as long as possible. Also, the parts of the poles that are not used for the posts must not be longer than the ones used for the posts. Donald can cut the poles as many times as he wants, and at any position he wants. However, cutting a pole takes time, so he wants to make as few cuts as possible while achieving his other goals.

How many cuts does Donald have to make to get the fence posts for his fence?

Input

The first line has two space-separated integers, KK and NN. The second line consists of KK space-separated integers p1p1, p2p2, …, pKpK, where pipi represents the length of the iith pole.

Output

Output the minimum number of cuts needed to build the fence.

Limits

1≤K≤N≤100001≤K≤N≤10000

1≤pi≤100001≤pi≤10000

Sample Input 1
1 2
3
Sample Output 1
1

Sample Input 2
2 5
4 2
Sample Output 2
4

题意:给定k根木棍,和需要分成的份数n,可以无限次切割各个木棍,使得切割而成的n份尽量长,
且长度相等,各个木棍剩余的部分不能比它长,求切割的最小次数。

分析:可知关键点在于组成这n份的木棍长度,因为最长的长度确定了,次数也随之确定,所以我们二分切割的长度,
check函数怎么写?怎么保证剩余部分小于这个长度呢?贪心处理,每根木棍能切多少切多少,如果是正好切,那么切的次数是份数-1.
二分下界是0,上界是n,指定一个精度,然后二分不断逼近这个最大值,最后再计算一遍份数就可以了。
这里浮点数计算存在误差,所以在判断浮点数相等的部分就让它们相减小于一个极小值就认为是相等

习惯性的用1e-6来判断浮点数和整数是否相等,但是这里全都用1e-6判断会WA,用1e-1到1e-5的任意的都可以,但不能用1e-6,这和题目的测试数据有关吧
这里写图片描述

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,k;
const int N=10005;
const double eps=1e-6;
int a[N];
int check(double p)///判断是否能得到n份尽可能长的木棍
{
    int sum=0;
    for(int i=0;i<k;i++)
    {
        int t=(int)(1.0*a[i]/p);
        if(fabs(1.0*t*p-a[i])<=eps) t--;
        sum+=t;
    }
    return sum>=n?1:0;///需要n份
}
int main()
{
    while(~scanf("%d%d",&k,&n))
    {
        for(int i=0;i<k;i++)
            scanf("%d",&a[i]);
        double l=0,r=n,mid,MAX;
        while(r-l>=eps)///二分法,一直找到最大的满足条件的MAX
        {
            mid=(l+r)/2.0;
            if(check(mid))
            {
                MAX=mid;
                l=mid;
            }
            else r=mid;
        }
        int ans=0;
        for(int i=0;i<k;i++)
        {
            int t=(int)(1.0*a[i]/MAX);//MAX为满足题目条件的最大长度
            if(fabs(1.0*t*MAX-a[i])<=1e-1) ///这里的精度判断不能比1e-5小,可以是1e-1到1e-5
               t--;
            ans+=t;
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值