Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
First strip away the mandatory spending. Everyone must get at least , so the only real budget is
Making friend happy by money costs an extra . Making them happy by box costs no extra money, but consumes one compatible box.
Think of paying the extra as removing friend from the box problem. They are already happy, so boxes only need to deal with the friends you did not upgrade.
For any remaining set of friends, the minimum number who must stay unhappy is
That is just Hall's condition on these nested suffixes. If too many friends need beauty at least , the excess is screwed unless upgraded.
Binary search the number of friends we allow to be unhappy. For this , we need to upgrade enough friends so that for every beauty threshold :
To find the cheapest upgrades for a fixed , scan thresholds from high to low. Keep a min-heap of upgrade costs of all friends with at least the current threshold. If the current suffix requires more upgraded friends, pop the cheapest available ones. This greedy works because higher-threshold requirements are stricter and must be satisfied before lower ones get more options.
Let’s separate the unavoidable part from the actual choice.
Every friend must receive a gift worth at least , and the statement guarantees
So spend that immediately. Define
as the extra budget, and
as the extra cost to make friend happy by money.
Now friend can be made happy in exactly one of two useful ways:
Using both is just lighting money on fire, which is usually a bad Codeforces strategy.
Key Reframe
If we pay for a friend, they are happy no matter what box they get. So for the box-matching part, that friend can be treated as removed.
After choosing some upgraded friends, the remaining friends can only be made happy with boxes. We need to know how many of those remaining friends cannot be boxed.
For any threshold , consider all remaining friends with . They can only use boxes with beauty . Therefore, if
and
then at least
of those friends cannot get a valid box.
Taking the worst threshold gives the exact number of remaining friends who must stay unhappy:
Why exact? Because these constraints are nested suffix constraints. A friend requiring beauty at least is also counted in every lower threshold like . For this kind of chain, Hall’s condition reduces exactly to checking every suffix. If every suffix has enough boxes after allowing failures, greedy matching works.
So the final number of happy friends is
Thus we want to spend at most upgrade coins to make as small as possible.
Binary Search on the Number of Unhappy Friends
Suppose we allow at most friends to be unhappy.
For every threshold , after upgrades we need
Let be the original number of friends with . If we upgrade friends among those with , then remaining friends in that suffix equal .
So we need
or
Define
For this fixed , our job is:
Choose minimum total upgrade cost such that for every , at least upgraded friends have .
If that minimum cost is at most , then unhappy friends is feasible.
Feasibility is monotonic: if works, any larger also works. So binary search the smallest feasible .
Greedy Check for a Fixed
Scan from down to .
Maintain a min-heap of upgrade costs of all friends with that we have not already upgraded.
Also maintain chosen, the number of upgraded friends selected so far. Since we scan downward, all selected friends always have , so they count for the current suffix.
At threshold , we need at least
selected friends from this suffix.
If chosen < R_v, we must select more friends. The cheapest valid choice is simply the cheapest available cost in the heap. Pop until chosen == R_v.
This greedy is correct because when processing threshold , only friends with can help. Future lower thresholds will only add more eligible friends, but they cannot help retroactively with stricter higher thresholds. So whenever we are forced to pick, picking the cheapest currently eligible friend is optimal. No drama, no DP circus.
Complexity
For one check, every friend enters the heap once and can be popped at most once, so it costs
Binary search adds a factor of .
Across all test cases:
which is fine for total input size.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m;
ll k;
cin >> n >> m >> k;
vector<int> boxCnt(m + 2, 0);
for (int i = 0; i < m; i++) {
int a;
cin >> a;
boxCnt[a]++;
}
vector<vector<ll>> costsAt(m + 2);
vector<int> friendCnt(m + 2, 0);
ll base = 0;
for (int i = 0; i < n; i++) {
int x;
ll y, z;
cin >> x >> y >> z;
base += y;
costsAt[x].push_back(z - y);
friendCnt[x]++;
}
ll budget = k - base;
vector<int> friendSuf(m + 3, 0), boxSuf(m + 3, 0);
for (int v = m; v >= 1; v--) {
friendSuf[v] = friendSuf[v + 1] + friendCnt[v];
boxSuf[v] = boxSuf[v + 1] + boxCnt[v];
}
auto feasible = [&](int unhappy) -> bool {
priority_queue<ll, vector<ll>, greater<ll>> pq;
ll spent = 0;
int chosen = 0;
for (int v = m; v >= 1; v--) {
for (ll c : costsAt[v]) pq.push(c);
int need = friendSuf[v] - boxSuf[v] - unhappy;
while (chosen < need) {
if (pq.empty()) return false;
spent += pq.top();
pq.pop();
chosen++;
if (spent > budget) return false;
}
}
return true;
};
int lo = 0, hi = n;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (feasible(mid)) hi = mid;
else lo = mid + 1;
}
cout << n - lo << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m;
ll k;
cin >> n >> m >> k;
vector<int> boxCnt(m + 2, 0);
for (int i = 0; i < m; i++) {
int a;
cin >> a;
boxCnt[a]++;
}
vector<vector<ll>> costsAt(m + 2);
vector<int> friendCnt(m + 2, 0);
ll base = 0;
for (int i = 0; i < n; i++) {
int x;
ll y, z;
cin >> x >> y >> z;
base += y;
costsAt[x].push_back(z - y);
friendCnt[x]++;
}
ll budget = k - base;
vector<int> friendSuf(m + 3, 0), boxSuf(m + 3, 0);
for (int v = m; v >= 1; v--) {
friendSuf[v] = friendSuf[v + 1] + friendCnt[v];
boxSuf[v] = boxSuf[v + 1] + boxCnt[v];
}
auto feasible = [&](int unhappy) -> bool {
priority_queue<ll, vector<ll>, greater<ll>> pq;
ll spent = 0;
int chosen = 0;
for (int v = m; v >= 1; v--) {
for (ll c : costsAt[v]) pq.push(c);
int need = friendSuf[v] - boxSuf[v] - unhappy;
while (chosen < need) {
if (pq.empty()) return false;
spent += pq.top();
pq.pop();
chosen++;
if (spent > budget) return false;
}
}
return true;
};
int lo = 0, hi = n;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (feasible(mid)) hi = mid;
else lo = mid + 1;
}
cout << n - lo << '\n';
}
return 0;
}