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.
Only the current total modulo matters. If the current remainder is , then buying price gives bonus exactly when .
Because every , one item can increase the loyalty level by at most one. So the number of bonus-giving purchases is fixed: .
Since exactly items give bonus, the best possible score is at most the sum of the largest prices. The main question is whether we can force those exact items to be the bonus items.
Sort the array. Reserve the largest values as bonus items, and use the other values as padding to raise the current remainder before each reserved item.
Process reserved items from smallest to largest. Before current reserved item , keep taking the smallest padding items while rem + b < X, then buy . Padding cannot accidentally trigger, since each padding item is at most .
Let
After all purchases, the final loyalty level is
Also, since every item has price at most , buying one item can increase the loyalty level by at most one. Therefore the number of purchases that give bonus points is fixed:
So we are not maximizing how many bonus events happen. That number is already locked in. The store did the math, rude but fair. We only choose which items become bonus items.
The maximum possible score is clearly the sum of the largest prices. No order can score more, because only items score. So if we can build an order where the largest prices are exactly the trigger purchases, we are done.
Trigger Condition
Suppose the current total spent is , and define
Buying an item of price increases the loyalty level exactly when
If this happens, we earn points, and the new remainder is
So we want to use smaller non-scoring items to build up the remainder, then use a large scoring item to cross the next multiple of .
Construction
Sort the prices increasingly.
Split them into two groups:
small: the first elements,big: the last elements.The answer value is
Now build the order like this:
rem, the current total modulo .big from smallest to largest.rem + b < X, output the smallest unused item from small and add it to rem.rem = (rem + b) % X.Why Small Items Do Not Steal Bonus
When we output a small item, we are inside the loop where
Every unused small item is at most , because all small items are outside the largest elements, and the big items are processed from smallest to largest. Therefore
So no small item triggers bonus. Nice. The cheap stuff stays padding.
Why Each Big Item Triggers
The loop before stops only once
Then buying increases the loyalty level, so earns bonus points.
Why We Cannot Run Out Of Padding
Assume we are about to process some big item , and we have already created some number of crossings. If even after using all remaining small items we still had rem + b < X, then the current item plus all available padding would contribute less than one full block of size .
All future big items are at most each. If there are future big items, they can contribute at most . So the remaining total would be less than
But from this point onward, the final total still needs exactly more loyalty increases. That requires at least remaining mass after including the current remainder. Contradiction.
So the greedy always has enough padding to make the current big item trigger.
Optimality
There are exactly bonus purchases in every possible order. Our construction makes exactly the largest prices become those bonus purchases. Therefore the score is the maximum possible.
Complexity
Sorting dominates:
per test case. The construction is linear. Since the total over all test cases is at most , this easily fits.
#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;
ll X;
cin >> n >> X;
vector<ll> a(n);
ll total = 0;
for (ll &v : a) {
cin >> v;
total += v;
}
sort(a.begin(), a.end());
int k = (int)(total / X);
ll ans = 0;
for (int i = n - k; i < n; i++) ans += a[i];
vector<ll> order;
ll rem = 0;
int small = 0;
for (int big = n - k; big < n; big++) {
while (small < n - k && rem + a[big] < X) {
order.push_back(a[small]);
rem += a[small];
small++;
}
order.push_back(a[big]);
rem = (rem + a[big]) % X;
}
while (small < n - k) {
order.push_back(a[small]);
small++;
}
cout << ans << '\n';
for (int i = 0; i < n; i++) {
if (i) cout << ' ';
cout << order[i];
}
cout << '\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;
ll X;
cin >> n >> X;
vector<ll> a(n);
ll total = 0;
for (ll &v : a) {
cin >> v;
total += v;
}
sort(a.begin(), a.end());
int k = (int)(total / X);
ll ans = 0;
for (int i = n - k; i < n; i++) ans += a[i];
vector<ll> order;
ll rem = 0;
int small = 0;
for (int big = n - k; big < n; big++) {
while (small < n - k && rem + a[big] < X) {
order.push_back(a[small]);
rem += a[small];
small++;
}
order.push_back(a[big]);
rem = (rem + a[big]) % X;
}
while (small < n - k) {
order.push_back(a[small]);
small++;
}
cout << ans << '\n';
for (int i = 0; i < n; i++) {
if (i) cout << ' ';
cout << order[i];
}
cout << '\n';
}
return 0;
}