//给你一个整数数组 nums ,其中 nums[i] 表示第 i 个袋子里球的数目。同时给你一个整数 maxOperations 。 
//
// 你可以进行如下操作至多 maxOperations 次: 
//
// 
// 选择任意一个袋子,并将袋子里的球分到 2 个新的袋子中,每个袋子里都有 正整数 个球。
//
// 
// 比方说,一个袋子里有 5 个球,你可以把它们分到两个新袋子里,分别有 1 个和 4 个球,或者分别有 2 个和 3 个球。 
// 
// 
// 
//
// 你的开销是单个袋子里球数目的 最大值 ,你想要 最小化 开销。 
//
// 请你返回进行上述操作后的最小开销。 
//
// 
//
// 示例 1: 
//
// 
//输入:nums = [9], maxOperations = 2
//输出:3
//解释:
//- 将装有 9 个球的袋子分成装有 6 个和 3 个球的袋子。[9] -> [6,3] 。
//- 将装有 6 个球的袋子分成装有 3 个和 3 个球的袋子。[6,3] -> [3,3,3] 。
//装有最多球的袋子里装有 3 个球,所以开销为 3 并返回 3 。
// 
//
// 示例 2: 
//
// 
//输入:nums = [2,4,8,2], maxOperations = 4
//输出:2
//解释:
//- 将装有 8 个球的袋子分成装有 4 个和 4 个球的袋子。[2,4,8,2] -> [2,4,4,4,2] 。
//- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,4,4,4,2] -> [2,2,2,4,4,2] 。
//- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,4,4,2] -> [2,2,2,2,2,4,2] 。
//- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,2,2,4,2] -> [2,2,2,2,2,2,2,2] 。
//装有最多球的袋子里装有 2 个球,所以开销为 2 并返回 2 。
// 
//
// 示例 3: 
//
// 
//输入:nums = [7,17], maxOperations = 2
//输出:7
// 
//
// 
//
// 提示: 
//
// 
// 1 <= nums.length <= 10^5
// 1 <= maxOperations, nums[i] <= 10^9
// 
// Related Topics 堆 二分查找 
// 👍 16 👎 0

/*
* 1760 袋子里最少数目的球
* 2021-02-19 22:06:02
* @author oxygenbytes
*/ 
#include "leetcode.h" 
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public:
    int minimumSize(vector<int>& nums, int maxOperations) {
        // 将极小极大化问题转化为二分查找
        // 到了10^9,要么是O(log(m)) 要么是 O(1)
        // 将计算问题转化为判定问题,判定本身的难度要小于计算

        int left = 0, right = *max_element(nums.begin(), nums.end());

        while(left < right){
            int mid = left + right >> 1;
            int ops = 0;

            for(auto x : nums){
                ops += (x - 1) / mid;
            }
            // mid是数目, ops是操作
            if(ops <= maxOperations) right = mid;  // ops满足条件,继续探索mid下界
            else left = mid + 1; // ops不满足
        }

        return left;
    }
};
//leetcode submit region end(Prohibit modification and deletion)