---
# System prepended metadata

title: 2233. Maximum Product After K Increments
tags: [Leetcode, Priority Queue, Smear Top Elements, Medium, Math, Greedy]

---

# 2233. Maximum Product After K Increments
###### tags: `Leetcode` `Medium` `Math` `Greedy` `Priority Queue` `Smear Top Elements`
Link: https://leetcode.com/problems/maximum-product-after-k-increments/description/
## 思路
尽量把k加在比较小的数字上面才能得到optimal结果
### 思路一 Priority Queue $O(klogN)$
### 思路二 Smear Top Elements
我们需要将```K```都分配给较小的元素，尽量“共同富裕”。那么我们将```nums```排序之后，需要将```K```分配给前多少个较小元素呢？显然我们要找到一个位置```p```，使得前```p```个元素之和加上```K```之后再进行平均分配，依然达不到第```p+1```个元素. 为什么呢？如果前```p```个元素进行共产主义之后，均值大于了第```p+1```个元素，那为什么不在前```p+1```个元素内进行“共同富裕”呢，这样就有更多的元素可以趋近一致，从而使乘积更大化。

那么我们如何快速定位这个p呢？我们定义```diff```数组```diff[i] = presum[i]-nums[i]*(i+1)```，表明将前```i+1```个元素都提升至与```nums[i]```相等的话，需要多少“支援”。可以知道，这个```diff```一定是递增的。于是我们可以用二分找到最大的```p```，使得恰好```diff[p]<=K```，意味着K的支援能够将```nums[0:p]```抹平，但是不足以将```nums[0:p+1]```抹平。

我们接下来的任务就是，我们先把```nums[0:p-1]```补到和```nums[0]```一样大 然后看```k```还剩多少 先平均分给```nums[0:p]```每个element ```k/p```这么多 接下来我们给前```k%p```个元素每个都加1即可
## Code
### 思路一 Priority Queue
```java=
class Solution {
    public int maximumProduct(int[] nums, int k) {
        Queue<Integer> pq = new PriorityQueue<>();
        int n = nums.length;
        for(int i=0; i<n; i++){
            pq.add(nums[i]);
        }
        for(int i=0; i<k; i++){
            pq.add(pq.poll()+1);
        }
        long ans = 1;
        int mod = 1000000007;
        while(!pq.isEmpty()){
            ans = (ans*pq.poll())%mod;
        }
        return (int)ans;
    }
}
```
### 思路二 Smear Top Elements
```java=
class Solution {
    public int maximumProduct(int[] nums, int k) {
        Arrays.sort(nums);
        int n = nums.length;
        long[] diff = new long[n];
        long presum = 0;
        for(int i=0; i<n; i++){
            presum += nums[i];
            diff[i] = (i+1)*(long)(nums[i])-presum;
        }
        
        int start = 0, end = n;
        while(start<end){
            int mid = start+(end-start)/2;
            if(diff[mid]<=k) start = mid+1;
            else end = mid;
        }

        //set all number before nums[start-1] equals to nums[start-1]
        for(int i=0; i<start; i++){
            k -= nums[start-1]-nums[i];
            nums[i] = nums[start-1];
        }
        //increase nums[0:(start-1)]
        //if k still larger than 0, increase first k%start elements by 1
        int each = k/start;
        int remain = k%start;
        for(int i=0; i<start; i++){
            nums[i] += each;
            if(i<remain) nums[i] += 1;
        }

        long ans = 1;
        int mod = 1000000007;
        for(int i=0; i<n; i++){
            ans = (ans*nums[i])%mod;
        }
        return (int)ans;
    }
}
```