[CodePlus 2017 11月赛&洛谷P4058]木材 题解(二分答案)

[CodePlus 2017 11月赛&洛谷P4058]木材

Description

有 n棵树,初始时每棵树的高度为 Hi ,第 i棵树每月都会长高 Ai。现在有个木料长度总量为 S的订单,客户要求每块木料的长度不能小于 L ,而且木料必须是整棵树(即不能为树的一部分)。现在问你最少需要等多少个月才能满足订单。

输入格式:
第一行 3个用空格隔开的非负整数 n,S,L,表示树的数量、订单总量和单块木料长度限制。
第二行 n 个用空格隔开的非负整数,依次为 H1,H2,...,Hn 。
第三行 n个用空格隔开的非负整数,依次为 A1,A2,...,An​ 。

输出格式:输出一行一个整数表示答案。

Solution

1.因为要求最少几个月,考虑进行二分答案;

2.考虑二分端点。因为有可能已开始就满足需求,所以左端点为0;

3.因为有两个约束条件,一个是总长度,一个是单根要求长度,我们无法确定二分的右端点到底是什么,所以我们需要知道到底哪一个才是真正的约束条件:

我们去比较要求的单根长度和把总任务分配到每一根的需求长度,取最大值就是实际的约束条件;那么二分的右端点实际上就是每棵树长高到约束条件的时间中的最大值,即:

for(i=1;i<=n;++i)if(h[i]<q)maxn=max(maxn,(q-h[i])/a[i]+1);

3.valid函数中验证的过程即为让sum加上所有经过x个月满足单棵树高度约束条件的树的高度,最后与总长度比较即可;

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int h[200200],a[200200];
unsigned long long n,m,s,i,j,k,minn=0,maxn=0,l,r,q;

inline int rd(){
    int x=0;
    bool f=true;
    char c;
    c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=false;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return f?x:-x;
} 

bool valid(unsigned long long x){
    unsigned long long sum=0;
    bool flag=1;
    for(i=1;i<=n;++i)
        if(h[i]+a[i]*x>=minn){
            if(flag)sum+=h[i]+a[i]*x;
            if(sum>=s)return true;
    }
    return false;
}

int main(){
    scanf("%lld%lld%lld",&n,&s,&minn);
    for(i=1;i<=n;++i)h[i]=rd();
    for(i=1;i<=n;++i)a[i]=rd();
    q=max(minn,s/n+1);
    for(i=1;i<=n;++i)if(h[i]<q)maxn=max(maxn,(q-h[i])/a[i]+1);  
    l=0;r=maxn;
    while(l<r){
        unsigned long long mid=(l+r)/2;
        if(valid(mid))r=mid;
        else l=mid+1;
    }
    printf("%lld\n",l);
    return 0;
}

二分答案的基础参考以前的随笔:http://www.cnblogs.com/COLIN-LIGHTNING/p/8543330.html

转载于:https://www.cnblogs.com/COLIN-LIGHTNING/p/8543473.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值