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.
The positions are fake difficulty. Since you can choose any subsequence, only the multiset of values matters. Sort and think in sorted order.
Fix . If one operation has median , then it needs chosen values on the left side and on the right side. The best such operation uses the smallest possible values on the left and the closest possible values on the right.
If you repeat operations with the same median , the right-side values only need to be decreased once, because after that they equal and can be reused as support. Meanwhile every operation can raise up to more small values.
For a fixed , there is an optimal strategy where every operation uses the same median. If you used medians , replacing the lower-median operation by another operation raises values to something no smaller and does not force extra right-side damage.
For fixed median index , optimize . The marginal gain from increasing by only gets worse: you raise already-larger left values and you must also lower a farther-right value. So binary search the last nonnegative marginal gain, using prefix sums for range sums.
Sort the array first. This is not a positional problem; the subsequence condition just means “pick any multiset of currently existing values.” After every operation we could sort again and nothing changes except making the reasoning less cursed.
Let the sorted array be
Choose an odd operation size
So every operation has values below/equal the median, one median value, and values above/equal the median.
One fixed operation
Suppose an operation has median . Then, in sorted-value language, it should use:
if we are only looking at one operation.
Why? The left side gets increased to , so we want the smallest values possible there. The right side gets decreased to , so we want the smallest values larger than the median there, i.e. the closest ones. Picking bigger right-side values is just donating points to the void. Bad trade.
For this to be legal, we need
Why one median is enough
Fix . Imagine using two operations with medians and , where .
The lower median can only raise some small values up to . If we instead use , those same small values can be raised to something at least as large. Also, the operation with median forces some values after to drop to . Replacing it with another operation of median does not create a worse forced decrease: the right-side support for can be reused.
So lower medians are never essential. Repeating this argument, for a fixed there is an optimal strategy where all operations use one median value .
That is the key simplification. Without it, this problem looks like subset soup. With it, it becomes a sorted-array optimization.
Value for fixed median and fixed
Fix median index and operation parameter .
Across at most operations, each operation can raise up to small values to . Therefore we can raise
values before .
The best values to raise are the smallest ones:
The right support values only need to be decreased once, and they should be
So the improvement is
Equivalently,
The answer is the original sum plus the maximum nonnegative gain over all . Taking means , which changes nothing, so the original sum is always available.
Optimizing for one median
Trying every for every would be , which is dead on arrival.
For fixed , look at the marginal gain from increasing to .
When increases by :
The newly raised left-side values are farther right than before, so they are larger or equal, meaning their benefit is smaller or equal. The newly decreased right-side value is also farther right, so its loss is larger or equal. Therefore the marginal gain is monotonically nonincreasing.
That means is unimodal/concave-ish over integer : keep increasing while the marginal gain is nonnegative, then stop. Binary search finds that last good .
For a candidate , define
The indices are the newly added left-side values. If all true left values are already used, this range may include itself as a dummy zero-gain value. That is fine and keeps the formula clean.
The marginal gain is nonnegative iff
Rearrange it into the code-friendly check:
All range sums come from prefix sums, so each check is .
For every median index , binary search in
Total complexity:
per test case after sorting, easily fine for .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
void solve() {
int n;
ll k;
cin >> n >> k;
vector<ll> a(n);
for (ll &x : a) cin >> x;
sort(a.begin(), a.end());
vector<ll> pref(n + 1, 0);
for (int i = 0; i < n; i++) pref[i + 1] = pref[i] + a[i];
auto sum = [&](int l, int r) -> ll {
if (l > r) return 0;
return pref[r + 1] - pref[l];
};
ll total = pref[n];
ll ans = total;
for (int i = 0; i < n; i++) {
int maxY = min(i, n - i - 1);
if (maxY == 0) continue;
auto good = [&](int y) -> bool {
int L = (int)min<ll>((ll)(y - 1) * k, i);
int R = (int)min<ll>((ll)y * k - 1, i);
ll cnt = R - L + 1;
ll cost = sum(L, R) + a[i + y];
return cost <= (cnt + 1) * a[i];
};
int lo = 1, hi = maxY + 1;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (good(mid)) lo = mid + 1;
else hi = mid;
}
int y = lo - 1;
if (y == 0) continue;
int R = (int)min<ll>((ll)y * k - 1, i);
ll changed = (ll)(R + 1) + y;
ll gain = changed * a[i] - (sum(0, R) + sum(i + 1, i + y));
ans = max(ans, total + gain);
}
cout << ans << '\n';
}
int main() {
setIO();
int t;
cin >> t;
while (t--) solve();
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
void solve() {
int n;
ll k;
cin >> n >> k;
vector<ll> a(n);
for (ll &x : a) cin >> x;
sort(a.begin(), a.end());
vector<ll> pref(n + 1, 0);
for (int i = 0; i < n; i++) pref[i + 1] = pref[i] + a[i];
auto sum = [&](int l, int r) -> ll {
if (l > r) return 0;
return pref[r + 1] - pref[l];
};
ll total = pref[n];
ll ans = total;
for (int i = 0; i < n; i++) {
int maxY = min(i, n - i - 1);
if (maxY == 0) continue;
auto good = [&](int y) -> bool {
int L = (int)min<ll>((ll)(y - 1) * k, i);
int R = (int)min<ll>((ll)y * k - 1, i);
ll cnt = R - L + 1;
ll cost = sum(L, R) + a[i + y];
return cost <= (cnt + 1) * a[i];
};
int lo = 1, hi = maxY + 1;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (good(mid)) lo = mid + 1;
else hi = mid;
}
int y = lo - 1;
if (y == 0) continue;
int R = (int)min<ll>((ll)y * k - 1, i);
ll changed = (ll)(R + 1) + y;
ll gain = changed * a[i] - (sum(0, R) + sum(i + 1, i + y));
ans = max(ans, total + gain);
}
cout << ans << '\n';
}
int main() {
setIO();
int t;
cin >> t;
while (t--) solve();
return 0;
}