```go
package main
import (
"bufio"
"os"
"strconv"
)
func main() {
// Initialize fast I/O
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
// Helper function to read next integer
readInt := func() int {
scanner.Scan()
x, _ := strconv.Atoi(scanner.Text())
return x
}
if !scanner.Scan() {
return
}
t, _ := strconv.Atoi(scanner.Text())
for ; t > 0; t-- {
n := readInt()
// Read array and count frequencies
counts := make([]int, n+1)
for i := 0; i < n; i++ {
counts[readInt()]++
}
// Count how many values have a specific frequency (bucket sort concept)
freqOfFreq := make([]int, n+1)
for v := 1; v <= n; v++ {
if c := counts[v]; c > 0 {
freqOfFreq[c]++
}
}
// Construct c: frequencies sorted in descending order
// Using 1-based indexing for convenient prefix sums
c := make([]int, 1, n+1)
for f := n; f >= 1; f-- {
cnt := freqOfFreq[f]
for k := 0; k < cnt; k++ {
c = append(c, f)
}
}
D := len(c) - 1 // Number of distinct values
// P: Prefix sums of sorted frequencies c
P := make([]int, D+1)
for k := 1; k <= D; k++ {
P[k] = P[k-1] + c[k]
}
// cPrime: Conjugate partition of c
// cPrime[x] is the number of values with frequency >= x
cPrime := make([]int, n+2)
cur := 0
for x := n; x >= 1; x-- {
cur += freqOfFreq[x]
cPrime[x] = cur
}
// PPrime: Prefix sums of cPrime
// PPrime[j] = sum(cPrime[x] for x=1 to j) = sum(min(c_k, j))
PPrime := make([]int, n+2)
for x := 1; x <= n+1; x++ {
PPrime[x] = PPrime[x-1] + cPrime[x]
}
// ans[k] will store the minimum operations to remove exactly k elements
ans := make([]int, n+1)
lastRemoved := 0
// Iterate on the number of operations M
// We calculate maxRem(M), the maximum elements we can remove in M operations.
// Since maxRem(M) is non-decreasing, we can fill the answers for ranges.
for M := 1; lastRemoved < n; M++ {
maxRem := 0
// We can split M operations into i operations of Type 1 (removing specific values)
// and j = M - i operations of Type 2 (removing distinct sets).
// Limit i by D because we can't choose more distinct values than available.
limitI := M
if limitI > D {
limitI = D
}
for i := 0; i <= limitI; i++ {
j := M - i
// Calculate contribution from j Type 2 operations
// This removes min(count[v], j) for all v.
// This equals sum of first j columns of the Ferrers diagram => PPrime[j]
var term1 int
if j >= n+1 {
term1 = PPrime[n+1]
} else {
term1 = PPrime[j]
}
// Calculate contribution from i Type 1 operations
// We pick i values with the largest remaining counts after j Type 2 ops.
// Remaining count for value k is max(0, c[k] - j).
// We sum this for the largest i values.
// c[k] - j > 0 implies c[k] > j, which implies k <= cPrime[j+1].
var p int
if j < n {
p = cPrime[j+1]
} else {
p = 0
}
// We sum (c[k] - j) for k from 1 to min(i, p)
lim := i
if p < lim {
lim = p
}
// Sum is (sum(c[k]) for k=1..lim) - lim * j
term2 := P[lim] - lim*j
currentTotal := term1 + term2
if currentTotal > maxRem {
maxRem = currentTotal
}
}
if maxRem > n {
maxRem = n
}
// If we can remove more elements with M ops than with M-1, update answers
if maxRem > lastRemoved {
for k := lastRemoved + 1; k <= maxRem; k++ {
ans[k] = M
}
lastRemoved = maxRem
}
}
// Output results for remaining size x = 0 to n-1
// Remaining size x corresponds to removing n-x elements.
for x := 0; x < n; x++ {
if x > 0 {
writer.WriteByte(' ')
}
writer.WriteString(strconv.Itoa(ans[n-x]))
}
writer.WriteByte('\n')
}
}
```