#include <bits/stdc++.h>
using namespace std;
/*
Problem: Minimum Operations to Reduce Total Weight
You are given:
- an integer n
- an integer k
- an array bags of length n where bags[i] represents the weight of the i-th bag
You want to make the total sum of all bag weights at most k.
In one operation, you can do exactly one of the following:
1) Decrease the weight of any one bag by 1
Example: if bags[i] = 7, after one operation it can become 6
2) Make one bag's weight equal to another bag's weight
Example: if bags[i] = 10 and bags[j] = 4, you may set bags[i] = bags[j], so bags[i] becomes 4
Your task is to find the minimum number of operations required to make:
bags[0] + bags[1] + ... + bags[n-1] <= k
Important points:
- Bag weights are allowed to become negative
- You can perform any number of operations
- Each decrease by 1 costs one operation
- Each copy operation also costs one operation
------------------------------------------------------------
Example:
Input:
n = 5
k = 10
bags = [5, 1, 3, 7, 9]
Output:
minimum number of operations needed so that total sum <= 10
------------------------------------------------------------
Idea used in this solution:
After sorting the array, the best strategy can be thought of like this:
- reduce the smallest element to some value x
- make some number of the largest elements equal to x
Why?
Because copying a large value down to a smaller one is often much cheaper than decreasing it one by one.
So for every possible number of largest elements we decide to overwrite, we calculate:
- what the smallest value x should be
- how many decrement operations are needed
- how many copy operations are needed
Then we take the minimum over all choices.
Time Complexity: O(n log n)
Space Complexity: O(n)
*/
class Solution {
private:
// Returns floor(a / b) for b > 0
long long floorDivide(long long a, long long b) {
if (a >= 0) return a / b;
return -((-a + b - 1) / b);
}
public:
long long minMovesToLimitWeight(int n, long long k, vector<long long>& bags) {
sort(bags.begin(), bags.end());
long long totalSum = 0;
for (long long weight : bags) {
totalSum += weight;
}
// If the sum is already within limit, no operation is needed
if (totalSum <= k) return 0;
// prefix[i] = sum of first i elements
vector<long long> prefix(n + 1, 0);
for (int i = 0; i < n; i++) {
prefix[i + 1] = prefix[i] + bags[i];
}
/*
Main idea:
Try taking the smallest element and reducing it to some value x.
Also try copying that x into the largest 'take' elements.
Then:
- copy cost = take
- decrease cost = bags[0] - x
*/
long long answer = totalSum - k; // worst case: only use decrement operations
for (int take = 0; take < n; take++) {
// Sum of the largest 'take' elements
long long largestPart = prefix[n] - prefix[n - take];
// Sum of elements that remain unchanged
long long fixedPart = totalSum - bags[0] - largestPart;
/*
New total after changes:
fixedPart + (take + 1) * x
We need:
fixedPart + (take + 1) * x <= k
So:
x <= (k - fixedPart) / (take + 1)
Since x may be negative, use floor division carefully.
*/
long long allowedX = floorDivide(k - fixedPart, take + 1);
// We can only decrease the smallest value, not increase it
long long finalSmallest = min(bags[0], allowedX);
long long operations = take + (bags[0] - finalSmallest);
answer = min(answer, operations);
}
return answer;
}
};
int main() {
Solution sol;
vector<long long> bags = {5, 1, 3, 7, 9};
cout << sol.minMovesToLimitWeight(5, 10, bags) << '\n';
return 0;
}