分石子-牛客网

题目描述

牛牛有n堆石子堆,第i堆一共有ai个石子。
牛牛可以对任意一堆石子数量大于1的石子堆进行分裂操作,分裂成两堆新的石子数量都大于等于1的石子堆。

现在牛牛需要通过分裂得到m堆石子,他想知道这m堆石子的最小值最大可以是多少?

示例1

输入

3,5,[3,5,6]

输出

2

说明

把5分裂成2和3

把6分裂成2和4

得到五堆石子[3,2,3,2,4]

备注:

1≤n≤1e5,n≤m≤∑ai,1≤ai≤1e9

第一个参数n代表石子堆的个数
第二个参数m表示需要得到的石子堆数。
第三个参数vector a代表每堆石子堆的石子个数

思路:令res表示分裂后m堆的最小值,res一定在[1, min{a[i], i=0,1...,n-1}]区间内,记左右区间分别为left, right。mid初始值去区间中值,即mid=left+(right-left)/2,利用二分思想不断找到mid的最终值。因为要求最小值最大,所以分堆的时候会尽量使每一堆的数据尽量均匀且接近最小值mid,具体地,对于其中一对a[i],在最小堆值为mid的条件下,最多可分为a[i]/mid堆。记所有堆可分别的堆数位cnt(a[0]/mid+....+a[n-1]/mid),若cntm,需增大mid,设左边界left=mid+1;若cnt==m,也不一定就是最终答案,因为mid稍微增大一点可能cnt的值并不会改变,还要继续向后找,left=mid+1.

public:
    /**
     * 分石子
     * @param n int整型 
     * @param m long长整型 
     * @param a int整型vector 
     * @return int整型
     */
    int solve(int n, long long m, vector& a) {
        // write code here
        long long l = 1, r = *min_element(a.begin(), a.end());
        while (l<=r)
        {
            long long mid = l + (r-l)/2;
            long long cnt = 0;
            for (auto x: a)
                cnt += x/mid;
            if (cnt < m)
                r = mid - 1;
            else
                l = mid + 1;
        }
        return r;
    }

题目:牛客网https://www.nowcoder.com/practice/1ea5b4eaeff841a4918931791b000756?tpId=110&&tqId=33486&rp=1&ru=/activity/oj&qru=/ta/job-code/question-ranking

你可能感兴趣的:(编程,#二分法)