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 frequencies matter. Positions are pure noise here; deleting the 3rd copy of value 7 is no different from deleting the 1st copy.
Separate operations into two species: distinct-value operations and same-value operations. If you decide to use h distinct-value operations, then any one value can lose at most h copies through those operations.
So after h distinct-value operations, a value with frequency f has excess max(f-h,0). One same-value operation can delete all of that excess for one chosen value.
For fixed h and v same-value operations, the best choice is greedy: take the v largest excesses. Sorting frequencies decreasing means those excesses are already in the same order.
Do not loop over all h*v pairs. For a fixed h, only frequencies greater than h have positive excess, and sum_h count(f_i > h) = sum_i f_i = n. That is the whole trick.
Kill the positions
The array order is a scam here. Operations only care whether chosen values are equal or all different, so the whole problem depends only on the frequency of each value.
Let the positive frequencies be sorted:
.
Think of each value as a vertical pile of copies. A same-value operation deletes from one pile. A distinct-value operation deletes at most one copy from each pile, like shaving off one horizontal layer.
Fix the number of distinct-value operations
Suppose we decide to use exactly distinct-value operations.
For one value with frequency , those operations can delete at most copies of it, because each distinct-value operation can include that value only once.
So the total number deleted by the distinct-value operations is at most
.
This upper bound is actually reachable: for operation layer , take one copy from every value that still has a copy at that layer. All chosen values in one such operation are distinct, so it is legal.
After these distinct operations, value still has an excess of
copies that distinct operations did not handle.
Now add same-value operations. One same-value operation can delete all remaining excess of one chosen value. Using two same-value operations on the same value is never useful for maximizing deletions, because you could merge them. So with same-value operations, you should pick the largest excesses.
Since the frequencies are sorted decreasing, the excesses are also sorted decreasing. Therefore, for fixed and , the maximum removed count is
.
That gives every possible strategy type: distinct-value operations and same-value operations, for total operations.
The efficient part
Naively trying every pair looks scary. It is not, if you only scan useful .
For a fixed , only frequencies with have positive excess. Let
.
For this , it is enough to try . Larger would add zero useful deletion, so it cannot improve the minimum operation count.
The magic count is:
.
Why? Each copy in a pile contributes to exactly one layer count. So across all , the total scanning work is linear after sorting. No quadratic nonsense, no heroic suffering.
For each :
best[h+v].Here best[t] means the maximum number of elements removable using exactly this counted mix of useful operations. Then take prefix maximums so best[t] means maximum removable using at most operations.
Turning maximum deletion into exact final size
For target final size , we need to delete
elements.
If best[t] >= k, then some plan deletes at least elements in at most operations. We can shrink the chosen sets inside those operations to delete exactly : a subset of an all-equal set is still all equal, and a subset of an all-distinct set is still all distinct. Empty operations are just skipped.
So the answer for is the smallest such that best[t] >= n-x.
Complexity
Sorting frequencies costs . The layer scanning costs . Over all tests, this is easily fine for .
#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;
cin >> n;
vector<int> cnt(n + 1, 0);
for (int i = 0; i < n; i++) {
int x;
cin >> x;
cnt[x]++;
}
vector<int> f;
for (int x = 1; x <= n; x++) {
if (cnt[x] > 0) f.push_back(cnt[x]);
}
sort(f.rbegin(), f.rend());
int m = (int) f.size();
int maxf = f[0];
vector<int> best(n + 1, 0);
int q = m;
int residual = n;
for (int h = 0; h <= maxf; h++) {
while (q > 0 && f[q - 1] <= h) q--;
int removed = n - residual;
best[h] = max(best[h], removed);
for (int v = 1; v <= q; v++) {
removed += f[v - 1] - h;
best[h + v] = max(best[h + v], removed);
}
if (h == maxf) break;
residual -= q;
}
for (int ops = 1; ops <= n; ops++) {
best[ops] = max(best[ops], best[ops - 1]);
}
vector<int> ans(n + 1);
int ops = 1;
for (int removed = 1; removed <= n; removed++) {
while (best[ops] < removed) ops++;
ans[removed] = ops;
}
for (int x = 0; x < n; x++) {
if (x) cout << ' ';
cout << ans[n - x];
}
cout << '\n';
}
}#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;
cin >> n;
vector<int> cnt(n + 1, 0);
for (int i = 0; i < n; i++) {
int x;
cin >> x;
cnt[x]++;
}
vector<int> f;
for (int x = 1; x <= n; x++) {
if (cnt[x] > 0) f.push_back(cnt[x]);
}
sort(f.rbegin(), f.rend());
int m = (int) f.size();
int maxf = f[0];
vector<int> best(n + 1, 0);
int q = m;
int residual = n;
for (int h = 0; h <= maxf; h++) {
while (q > 0 && f[q - 1] <= h) q--;
int removed = n - residual;
best[h] = max(best[h], removed);
for (int v = 1; v <= q; v++) {
removed += f[v - 1] - h;
best[h + v] = max(best[h + v], removed);
}
if (h == maxf) break;
residual -= q;
}
for (int ops = 1; ops <= n; ops++) {
best[ops] = max(best[ops], best[ops - 1]);
}
vector<int> ans(n + 1);
int ops = 1;
for (int removed = 1; removed <= n; removed++) {
while (best[ops] < removed) ops++;
ans[removed] = ops;
}
for (int x = 0; x < n; x++) {
if (x) cout << ' ';
cout << ans[n - x];
}
cout << '\n';
}
}