Given an array usage where usage[i] is the memory used by the app during the ith task, and an integer k representing how many optimization actions you can apply, return the minimum possible maximum memory usage after optimizations. One optimization action reduces a single task's memory usage by half using floor division. You may apply multiple actions to the same task.
Example 1:
Input: usage = [10, 20, 7], k = 4
Output: 5
Explanation: Apply actions to 20 -> 10 -> 5 and 10 -> 5, so the final array can be [5, 5, 7], then one more action on 7 -> 3 gives max 5.
Example 2:
Input: usage = [1, 8, 8], k = 2
Output: 4
Explanation: Apply one action to each 8, producing [1, 4, 4]. The maximum becomes 4.
1 <= usage.length <= 10^50 <= usage[i] <= 10^90 <= k <= 10^9