For the convenience, we use to denote in article below.
Analysis
Gain From One Child
Consider if we chose children at time , what could we add to the final sum?
If not considering our choice, the lost of the happiness should be:
- If , this means the will goes to before the procedure finished, so the maximum decrease of the value is from to , that is,
- If , that means never reach , the decrease value is exactly the round . So we have .
Now take our choice operation into consideration. If we chose a child at time , then the actual lost of happiness of this child should be:
- If , means we chose this child while it’s decreasing, this means if we chose this child, it should be decreasing from time to time , the actual decrease value .
- If , means this child’s happiness already stop decreasing, our action of choice actually has no effect, so .
In conclusion, we could know that for any child , if we choice it, the happiness value we could get will be:
Choose Child
Based on analysis above, we should be aware that the greedy strategy could be used for this question. That is, to ensure highest final sum, we should always choose child with largest initial happiness first.
Consider the formula of :
If we want to make larger, we need to make smaller, so we should put larger with smaller . And that, in this problem, means choose child with larger happiness sooner.
Code
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using std::priority_queue;
using std::vector;
bool debug = false;
struct MyMinHeap : std::priority_queue<int, std::vector<int>, std::greater<int>> {
void reserve(size_t n) { this->c.reserve(n); }
};
class Solution {
public:
long long maximumHappinessSum(vector<int>& happiness, int k) {
// min heap
MyMinHeap maxk;
maxk.reserve(k);
int cur, top;
// initial heap with k elements
for (int i = 0; i < k; ++i) {
maxk.push(happiness[i]);
}
// iterate while update
for (int i = k; i < happiness.size(); ++i) {
cur = happiness[i];
top = maxk.top();
// current elements smaller, just continue
if (cur <= top) {
continue;
}
// update elements
maxk.pop();
maxk.push(cur);
}
// at this point, all max-k elements are in the min heap
long long answer = 0;
int chooseTime, lost;
for (chooseTime = k - 1; chooseTime >= 0; --chooseTime) {
// get top element
cur = maxk.top();
maxk.pop();
if (debug) {
cout << "choosed: " << cur << endl;
}
// determine the lost of this element
lost = std::min({k, cur, chooseTime});
// update answer
answer += (cur - lost);
}
return answer;
}
};