


If N = 4, K = 2 and subjects = {50,100,300,400}
Assignment of problems can be done in the following ways among the two friends.
{} and {50,100,300,400}. Time required = max(0, 50+100+300+400) = max(0, 850) = 850
{50} and {100,300,400}. Time required = max(50, 100+300+400) = max(50, 800) = 800
{50, 100} and {300,400}. Time required = max(50+100, 300+400) = max(150, 700) = 700
{50,100,300} and {400}. Time required = max(50+100+300, 400) = max(450, 400) = 400
{50,100,300, 400} and {}. Time required = max(50+100+300+400, 0) = max(850, 0) = 850
So, out of all the above following ways, 400 is the lowest possible time.
The first line of input contains a single integer 'T', representing the number of test cases or queries to be run.
Then the 'T' test cases follow.
The first line of each test case contains a single space-separated two integers 'N' and 'K' representing the total subjects and friends.
The second line of each test case contains 'N' space-separated integers representing the problems of the array “subjects”.
For each test case, print the minimum possible time to solve all the problems.
You do not need to print anything. It has already been taken care of. Just implement the given function.
1 <= T <= 10
1 <= N, K <= 10^4
1 <= subjects[i] <= 10^9
Time limit: 1 sec
We want to assign N number of subjects among K friends. So consider this as dividing the array into K partitions, where each partition denotes the subjects assigned to one of the friends. Assume that we already have K-1 partitions i.e. we have already assigned the subjects to K-1 friends, and now we want to do the K th partition. So, this last divider can be put between i th and i+1 th subject for 1<=i<=N-1. Note that, putting the divider before the first element is identical to putting it after the last element.
So, after the K th partition, the total time can be calculated as the maximum of below conditions:
In the previous approach, the algorithm recursively calculates and compares every possible partition at every possible element, which has many overlapping subproblems. i.e. a recursive function computes the same sub-problems again and again. So we can use memoization to overcome the overlapping subproblems. To reiterate, memoization is when we store the results of all previously solved subproblems and return the minimum time required to solve the problems, from the dp[i][j] if we encounter the problem that has already been solved.
Since there are two states those are changing in the recursive function, i.e. N and K, so we use the 2-dimensional array dp[][] to store all the subproblems, where dp[i][j] will store the result from 0 to i th friend and from 0 to j th subject.
Another optimization that can be done is that, like in the previous approach, instead of calculating the sum of the array from subjects[i] to subjects[N-1] again and again, we can create a prefixSum array to store the prefix sum of the array subjects and get the sum from subjects[i] to subjects[N-1] in constant time.
minimumRequiredTimeUtil(subjects, N, K, dp, prefixSum):
The idea is to use a bottom-up dynamic programming approach instead of a memoization approach. Here also, for each partition we have the choices to put the divider between the i th and i+1 th subject for 1 <= i <= N-1. So, with the outer loop running from i = 2 to K and the inner loop running from j = 2 to N, we can use the recurrence relation of memoization approach as dp[i][j] = min(dp[i][j], max(dp[i-1][x], prefixSum[j-1] - prefixSum[x-1])) where 1 <= x <= j.
The idea here is to perform the binary search. We know that the binary search can be performed if the following conditions hold.
So, in order to perform a binary search, we need to detect a suitable search space first. For that, let’s find out the minimum possible value and the maximum possible value of the answer. We can safely assume the lowest possible value of the answer is 0 when the array is empty. However, the highest possible value occurs when the value of K = 1. In that case, the answer is the sum of all the elements in the array “subjects”. So, the highest possible value is the sum of the array “subjects”. So, the range of the search space is [0, the sum of the array subjects].
Now, let us consider that we have t number of friends, so as the value in the above range decreases, the value of t increases and vice-versa. So, by performing the binary search in the range [0, the sum of the array subjects], for each mid in the range, we check whether it is possible to do K partitions such that the answer is mid. We can do so by implementing another function, say, checker. If it is possible to do K partitions for this value of mid, that means we have enough friends to solve the problems in the given time i.e. mid, so we update the upper bound of the range to mid - 1 storing the answer as mid. If it is not possible to do K partitions, that means we do not have enough friends to solve the problems in the given time, so we update the lower bound of the range to mid+1.
bool checker(subjects, N, K, mid):