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.
Giving cards without increasing the current prefix maximum is dead weight. Since the total is an upper bound, not an exact amount, any such cards should just be changed to .
So the only meaningful moves are “set a new record.” If the current record is and friend can carry cards, you may spend cards now, and then every remaining prefix gains at least instead of .
Try processing friends from left to right with a DP state that remembers two things: total cards already spent, and the current record value. The value stored is the happiness collected so far.
At friend , every state automatically gets happiness for this visit. Then, optionally, if is larger than the current record, you can choose a new record and spend cards.
Naively trying all old records and all new records is if you are careless. For transition into new record , you need the best previous state among records and budgets . Maintain prefix maxima over the record dimension for each budget, and the DP becomes .
We need choose integers with
and maximize
The trap is thinking every friend matters individually. They do not. Little A only remembers the current biggest pile of cards, so most chosen values are useless noise.
First cleanup
Suppose before friend the current maximum is . If we choose some , the prefix maximum does not change. It adds no future benefit either. Since we are not required to spend exactly cards, spending those cards is just burning budget for vibes. Bad vibes. Set it to instead.
So in an optimal solution, every positive nonzero choice is a new record:
That turns the problem into choosing a few record-breaking friends and their record values.
DP state
Process friends left to right. Since , we can afford states involving card budget and current maximum.
Let
be the maximum happiness after processing some prefix of friends, having spent exactly cards, with current prefix maximum equal to .
Impossible states are .
Initially:
For each friend with capacity , we do two conceptual steps.
Step 1: collect happiness for this visit
If the current maximum is , then after this friend's visit Little A gains , unless this friend sets a new record. It is easier to handle this by defining transitions directly for the chosen value at this friend.
For friend , from old state :
So the raw transitions are:
and
for every and .
This is correct, but doing all triples per friend would be too chunky: about .
Speeding up the record transition
For a fixed new record and final spent amount , the previous cost must be
The previous record can be anything smaller than :
Thus we need:
That is just a prefix maximum over for each budget.
Before processing a friend, build:
Then the best transition that creates record is:
We only allow it when .
Per friend transitions
For each friend:
Then replace with .
The answer is:
because the total number of cards may be at most , not exactly .
Why this works
The DP considers every relevant optimal action:
Since every optimal solution can be viewed as a sequence of record-setting moves plus zeroes, and every such move is represented by the DP, the result is optimal.
Complexity
There are states. For each friend, keeping states costs , building prefix maxima costs , and trying all new records and budgets costs .
So each test case runs in
with memory
With and the given sum constraints, this fits comfortably in C++.
#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;
const ll NEG = -(1LL << 60);
while (T--) {
int n, k;
cin >> n >> k;
vector<int> a(n);
for (int &x : a) cin >> x;
vector<vector<ll>> dp(k + 1, vector<ll>(k + 1, NEG));
dp[0][0] = 0;
for (int cap : a) {
vector<vector<ll>> ndp(k + 1, vector<ll>(k + 1, NEG));
for (int spent = 0; spent <= k; spent++) {
for (int mx = 0; mx <= k; mx++) {
if (dp[spent][mx] == NEG) continue;
ndp[spent][mx] = max(ndp[spent][mx], dp[spent][mx] + mx);
}
}
vector<vector<ll>> pref(k + 1, vector<ll>(k + 1, NEG));
for (int spent = 0; spent <= k; spent++) {
pref[spent][0] = dp[spent][0];
for (int mx = 1; mx <= k; mx++) {
pref[spent][mx] = max(pref[spent][mx - 1], dp[spent][mx]);
}
}
for (int v = 1; v <= cap; v++) {
for (int spent = v; spent <= k; spent++) {
ll best = pref[spent - v][v - 1];
if (best == NEG) continue;
ndp[spent][v] = max(ndp[spent][v], best + v);
}
}
dp.swap(ndp);
}
ll ans = 0;
for (int spent = 0; spent <= k; spent++) {
for (int mx = 0; mx <= k; mx++) {
ans = max(ans, dp[spent][mx]);
}
}
cout << ans << '\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;
const ll NEG = -(1LL << 60);
while (T--) {
int n, k;
cin >> n >> k;
vector<int> a(n);
for (int &x : a) cin >> x;
vector<vector<ll>> dp(k + 1, vector<ll>(k + 1, NEG));
dp[0][0] = 0;
for (int cap : a) {
vector<vector<ll>> ndp(k + 1, vector<ll>(k + 1, NEG));
for (int spent = 0; spent <= k; spent++) {
for (int mx = 0; mx <= k; mx++) {
if (dp[spent][mx] == NEG) continue;
ndp[spent][mx] = max(ndp[spent][mx], dp[spent][mx] + mx);
}
}
vector<vector<ll>> pref(k + 1, vector<ll>(k + 1, NEG));
for (int spent = 0; spent <= k; spent++) {
pref[spent][0] = dp[spent][0];
for (int mx = 1; mx <= k; mx++) {
pref[spent][mx] = max(pref[spent][mx - 1], dp[spent][mx]);
}
}
for (int v = 1; v <= cap; v++) {
for (int spent = v; spent <= k; spent++) {
ll best = pref[spent - v][v - 1];
if (best == NEG) continue;
ndp[spent][v] = max(ndp[spent][v], best + v);
}
}
dp.swap(ndp);
}
ll ans = 0;
for (int spent = 0; spent <= k; spent++) {
for (int mx = 0; mx <= k; mx++) {
ans = max(ans, dp[spent][mx]);
}
}
cout << ans << '\n';
}
return 0;
}