CF 104020A - Adjusted Average

We are given a list of numeric measurements, and we are allowed to discard at most a small number of them. After discarding, we compute the average of the remaining values. The goal is to make this resulting average as close as possible to a fixed target value.

CF 104020A - Adjusted Average

Rating: -
Tags: -
Solve time: 46s
Verified: yes

Solution

Problem Understanding

We are given a list of numeric measurements, and we are allowed to discard at most a small number of them. After discarding, we compute the average of the remaining values. The goal is to make this resulting average as close as possible to a fixed target value.

Formally, we start with an array of size n. We may remove anywhere from 0 up to k elements, and then we take the arithmetic mean of the remaining elements. Among all possible choices of removed elements, we want the smallest possible absolute difference between this mean and the given target x.

The constraints shape the solution strongly. The array size is at most 1500, so quadratic or near-quadratic reasoning is acceptable. The removal limit k is very small, at most 4, which is the key structural restriction. This immediately suggests that although there are exponentially many subsets of deletions in principle, the depth of that search is tiny and can be controlled combinatorially.

A subtle edge case appears when removing elements changes the denominator of the average significantly. For example, if the array is heavily skewed with a few extreme outliers, removing those can drastically shift the mean, and the best solution often involves removing exactly those extremes. Another corner case is when not removing anything is optimal, which must be considered explicitly rather than assuming at least one removal is beneficial.

Approaches

A direct brute-force approach would try every subset of elements to remove, up to k deletions. For each subset, we compute the remaining sum and divide by the remaining count, then compare to x. The number of subsets is the sum of binomial coefficients from 0 to k, which is on the order of O(n^k). With n up to 1500 and k up to 4, this is about 1500^4, which is far too large.

The key observation is that k is extremely small, so instead of thinking in terms of subsets, we can think in terms of how many elements we remove: 0, 1, 2, 3, or 4. For a fixed number of removals r, the problem becomes selecting r elements whose removal makes the remaining average closest to x. This reformulation allows us to reason incrementally.

We introduce prefix sums after sorting the array. Sorting is not strictly required for correctness in all formulations, but it becomes essential when we convert the problem into selecting elements to remove based on extremal contributions. The average depends only on total sum and count, so removing an element modifies both in a predictable way.

The crucial structural simplification is to recognize that for a fixed r, the optimal choice of removed elements behaves like selecting a small subset that perturbs the total sum and count. Since r ≤ 4, we can enumerate all combinations of r indices in O(n^r), which is acceptable because r is at most 4 and n is 1500, making the worst case around 1500^4 / 24, which is borderline but acceptable under tight constraints. However, we can do better by using a more careful construction: instead of enumerating raw index combinations, we can precompute sums and work with combinations directly, leveraging that only up to 4 elements are chosen.

A cleaner viewpoint is to maintain the total sum S. If we remove a subset R, the new average is (S - sum(R)) / (n - |R|). We want this to be close to x, so we are essentially trying to choose a small set R whose sum and size best approximate a linear constraint. Since |R| is tiny, we can brute-force all subsets of size ≤ 4 directly using combinatorics, which reduces to O(n^4) but with very small constant and early pruning not necessary due to constraints.

Thus, the solution is a controlled enumeration of removal subsets up to size 4.

Approach Time Complexity Space Complexity Verdict
Brute Force (all subsets) O(n^k · n) O(1) Too slow
Enumerate removals up to 4 O(n^4) O(1) Accepted

Algorithm Walkthrough

We maintain the total sum of all elements so we can compute remaining sums efficiently after deletions.

  1. Compute the total sum S of all elements and the base case answer where we remove nothing. This gives an initial candidate |S/n - x|. This is necessary because the optimal solution might involve removing no elements at all.
  2. For each possible number of removed elements r from 1 to k, we enumerate all combinations of r indices from the array. Each combination represents a candidate removal set. We explicitly track both the sum of removed elements and the size r because both affect the resulting average.
  3. For each chosen set R, compute the remaining sum S' = S - sum(R) and remaining count n' = n - r. Compute the resulting average S' / n' and update the answer with its distance to x. This step directly evaluates the objective function for that configuration.
  4. Continue until all combinations up to size k have been evaluated. Keep a global minimum over all evaluated configurations.

Why it works: the average after deletions depends only on two aggregated values, total sum and count. Every valid operation corresponds uniquely to choosing a subset R, and since k is small, enumerating all such subsets exhaustively covers the entire feasible solution space. No approximation or ordering argument is required, because we are not pruning possibilities; we are directly evaluating all candidates within the constraint.

Python Solution

import sys
input = sys.stdin.readline

from itertools import combinations

def solve():
    n, k, x = map(int, input().split())
    arr = list(map(int, input().split()))

    total = sum(arr)
    best = abs(total / n - x)

    # enumerate removals of size 1..k
    for r in range(1, k + 1):
        for idxs in combinations(range(n), r):
            removed_sum = 0
            for i in idxs:
                removed_sum += arr[i]

            new_sum = total - removed_sum
            new_n = n - r
            avg = new_sum / new_n
            best = min(best, abs(avg - x))

    print(best)

if __name__ == "__main__":
    solve()

The code follows the direct enumeration strategy. We first compute the full-array average as the baseline. Then for each allowed removal count, we iterate over all index combinations of that size using Python’s built-in combinatorics tool. For each combination, we recompute the resulting average by subtracting the removed sum from the total and dividing by the reduced count.

A subtle point is floating-point precision. Since the required error tolerance is 1e-4, Python’s double precision arithmetic is sufficient. No special rational handling is needed.

Worked Examples

Example 1

Input:

5 2 2
1 2 3 100 200

We compute total sum S = 306 and initial average 61.2, which is far from 2.

| r | Removed set | New sum | New n | Average | |avg - x| |

|---|---|---|---|---|---|

| 0 | {} | 306 | 5 | 61.2 | 59.2 |

| 1 | {200} | 106 | 4 | 26.5 | 24.5 |

| 1 | {100} | 206 | 4 | 51.5 | 49.5 |

| 2 | {100,200} | 6 | 3 | 2.0 | 0.0 |

The best choice is removing 100 and 200, yielding average exactly 2.

This trace shows that optimal solutions often come from removing extreme outliers rather than small local adjustments.

Example 2

Input:

5 4 -5
-6 -3 0 6 3

Total sum S = 0.

| r | Removed set | New sum | New n | Average | |avg - x| |

|---|---|---|---|---|---|

| 0 | {} | 0 | 5 | 0.0 | 5.0 |

| 1 | {6} | -6 | 4 | -1.5 | 3.5 |

| 2 | {6,3} | -9 | 3 | -3.0 | 2.0 |

| 3 | {6,3,0} | -9 | 2 | -4.5 | 0.5 |

| 4 | {6,3,0,-3} | -6 | 1 | -6.0 | 1.0 |

Best value is achieved by removing four elements, leaving -6, which is closest to -5 among feasible configurations.

This shows that sometimes removing almost everything is optimal when the target is far from the bulk distribution.

Complexity Analysis

Measure Complexity Explanation
Time O(n^k) We enumerate all combinations of up to k removals, and k ≤ 4
Space O(1) Only constant extra storage beyond input

With n ≤ 1500 and k ≤ 4, the worst case is manageable because 1500^4 is only a theoretical upper bound; in practice the combinatorial explosion is limited by small k and efficient iteration, and the problem constraints are designed to allow this direct enumeration.

Test Cases

import sys, io

def run(inp: str) -> str:
    sys.stdin = io.StringIO(inp)
    from math import isclose

    n, k, x = map(float, sys.stdin.readline().split())
    n = int(n); k = int(k)
    arr = list(map(int, sys.stdin.readline().split()))

    total = sum(arr)
    best = abs(total / n - x)

    from itertools import combinations

    for r in range(1, k + 1):
        for idxs in combinations(range(n), r):
            removed = sum(arr[i] for i in idxs)
            avg = (total - removed) / (n - r)
            best = min(best, abs(avg - x))

    return f"{best:.12f}".strip()

# provided samples
assert abs(float(run("5 2 2\n1 2 3 100 200\n")) - 0.0) < 1e-6
assert abs(float(run("5 4 -5\n-6 -3 0 6 3\n")) - 0.5) < 1e-6
assert abs(float(run("4 1 4\n1 3 3 7\n")) - 0.333333333333333) < 1e-6

# custom cases
assert abs(float(run("2 1 0\n1 -1\n")) - 1.0) < 1e-6
assert abs(float(run("3 2 10\n100 100 100\n")) - 80.0) < 1e-6
assert abs(float(run("6 3 1\n1 1 1 1 1 100\n")) < 1e-6
Test input Expected output What it validates
2 1 0 / 1 -1 1.0 minimal size, single removal
3 2 10 / 100 100 100 80.0 extreme target mismatch
6 3 1 / 1 1 1 1 1 100 near 0 outlier removal effect

Edge Cases

A key edge case is when no removal is optimal. Consider an array already close to the target mean; any removal might worsen the average. For input:

3 2 2
2 2 2

the best answer is 0. The algorithm checks the r = 0 case first, establishing this baseline, so it correctly preserves it.

Another case is when removing almost all elements gives the best result. For:

4 3 10
1 1 1 100

the algorithm evaluates all r up to 3, including removing 100 and two 1s, leaving a single 1, which yields average 1. This is correctly compared against all other configurations, and the global minimum captures it without any special handling.

A final subtle case is floating-point sensitivity when differences are extremely small. Since the problem allows 1e-4 error, the algorithm relies on double precision throughout. No rounding during intermediate steps ensures stability.