洛谷 P2440 木材加工 (二分答案)

P2440 木材加工

题意

给定N个木头及其长度,要求把这些木头切割成M块长度相同的小段木头(木头有可能有剩余),求小段木头的最大值。

比如:有两木头长度为 11 和 21, 要求切成 6 块, 那么每块最长就为 5。

1 ≤ N ≤ 100000 , 1 ≤ M ≤ 100000000 1 ≤ N ≤ 100000,1 ≤ M ≤ 100000000 1N1000001M100000000
原 木 长 度 : 1 到 100000000 原木长度:1到100000000 1100000000

思路

我们没有办法直接根据木块长度,和要切的块数去算最终小木块的长度。
最终小木块的长度只能在 0 到 100000000 之间。
不考虑时间复杂度,我们可以枚举木块长度,判断寻找可行长度的最大值。

但很明显这个问题的答案具有单调性,也就是说我们不用枚举木块长度,可以二分查找。

为什么说有单调性呢?

因为假设当前进行判断的木块长度为X,如果长度X可行,那么最终答案肯定大于等于X,如果X不可行,那么最终答案肯定小于X。
所以我们可以对 0 到 100000000 这个答案区间进行二分查找,准确来说是右边界二分查找,找到满足要求的最大值。

代码

右边界二分(17ms)

#include

using namespace std;

int n,m;
int a[100005];

bool check(int x)
{
    if(x==0)//长度为0肯定可行
        return true;
    int ans = 0;
    //累加当长度为x时,能切成的块数
    for(int i = 1; i <= n; ++i){
        ans += a[i]/x;
    }
    //大于等于m则表示可行
    return ans >= m;
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; ++i)
        cin >> a[i];
    int l = 0;
    int r = 100000001;
    //右边界二分
    while(l<r){
        int mid = l+(r-l)/2;
        if(check(mid))//判断mid是否满足要求
            l = mid+1;
        else
            r = mid;
    }
    cout << r-1 << endl;
    return 0;
}

你可能感兴趣的:(洛谷)