CF 105059F - Average of Averages

We are given an integer array and we look at every contiguous segment of it. For each segment, we compute its average value, meaning the sum of elements in that segment divided by its length. The task is to take all these segment averages and compute their overall mean.

CF 105059F - Average of Averages

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

Solution

Problem Understanding

We are given an integer array and we look at every contiguous segment of it. For each segment, we compute its average value, meaning the sum of elements in that segment divided by its length. The task is to take all these segment averages and compute their overall mean.

So instead of asking for a single subarray statistic, we are averaging a quantity that is itself an average over all subarrays. Every subarray contributes equally, regardless of its length.

The input size is large: up to 2 × 10^5 total elements across all test cases. This immediately rules out any approach that explicitly enumerates all subarrays, since there are n(n+1)/2 of them per test case. Even for n = 2 × 10^5, this is far beyond any feasible computation. A valid solution must reduce the problem to linear or near-linear work per test case.

A subtle issue appears if we try to aggregate using floating-point arithmetic too early. Because the number of subarrays can reach O(n^2), intermediate sums can exceed integer limits if not handled carefully, and precision errors can accumulate if we repeatedly divide instead of restructuring the formula.

A naive mistake often comes from thinking we can compute prefix averages and then average those. For example, on array [1, 2], prefix averages are 1 and 1.5, but their mean is 1.25, while the correct answer is (1 + 1.5 + 2)/3 = 1.5. This mismatch happens because subarrays are not represented evenly by prefix structure.

Approaches

The brute-force approach is straightforward: iterate over every pair (l, r), compute the sum of that subarray using prefix sums, divide by its length, and accumulate. This is correct because it directly follows the definition. The problem is performance. There are about n(n+1)/2 subarrays, and each subarray sum can be computed in O(1) with prefix sums, so the total complexity is O(n^2) per test case. With n up to 2 × 10^5, this becomes on the order of 10^10 operations, which is infeasible.

The key observation is that the expression is linear in the array values, so each element’s contribution can be analyzed independently. Instead of thinking in terms of subarrays, we switch perspective: fix an index i and ask how many times a[i] appears inside all subarray averages, and with what weight.

For any subarray (l, r) containing i, the element a[i] contributes a[i] / (r − l + 1) to the average of that subarray. So its total contribution is a[i] multiplied by the sum over all l ≤ i ≤ r of 1 / (r − l + 1). This transforms the global problem into a per-index contribution problem.

We then count how many subarrays include i with a given length. A subarray containing i with length k must choose its left endpoint in i − k + 1 to i, and its right endpoint is fixed by length. The number of such subarrays is exactly k choices are not independent in that form, so we reparameterize: for a fixed i, subarrays containing it are determined by choosing l and r such that l ≤ i ≤ r. The contribution weight depends only on distance from i to endpoints, and can be summed efficiently by reorganizing into contributions by subarray length.

This leads to a standard harmonic-weight structure: for each i, contributions depend on how many subarrays of each length include i, and each such subarray contributes a[i] / length. The final answer becomes a weighted sum over i where weights depend only on combinatorics of positions, and these weights can be precomputed in O(1) amortized per i using prefix harmonic accumulation.

A cleaner derivation comes from flipping summations:

We want

average over subarrays of (sum over i in subarray a[i] / length)

Swap sums:

sum over i of a[i] × (sum over subarrays containing i of 1 / length) divided by total number of subarrays.

Total subarrays is n(n+1)/2, so everything reduces to computing for each i the harmonic-style weight of all segments containing i. This can be computed in O(n) using prefix sums of harmonic numbers.

Approach Time Complexity Space Complexity Verdict
Brute Force O(n²) O(1) Too slow
Optimal O(n) O(n) Accepted

Algorithm Walkthrough

  1. Precompute an array H where H[k] is the sum of 1/1 + 1/2 + ... + 1/k. This allows fast aggregation of harmonic contributions for ranges of lengths. The reason this is useful is that subarray length is exactly the denominator structure appearing in each average.
  2. Compute the total number of subarrays T = n(n+1)/2. Every final contribution will be normalized by this value because we are averaging over all subarray averages.
  3. For each position i, compute how many subarrays include it with each possible length. A subarray of length k includes i if its left endpoint lies in a valid interval, and that interval length depends linearly on i and k. This structure ensures that the count of such subarrays can be expressed as a difference of prefix counts.
  4. Convert the contribution of a[i] into a sum over all possible lengths k of (number of subarrays of length k containing i) multiplied by 1/k. Instead of iterating k explicitly, use prefix harmonic values so that contributions of ranges of k can be computed in O(1).
  5. Accumulate the weighted contribution for each i into a global sum. This produces the numerator of the final answer.
  6. Divide the accumulated result by T to obtain the final average of averages.

Why it works

The key property is linearity of expectation over a uniform distribution of subarrays. Every subarray is equally likely in the final averaging, so we can treat the process as choosing a random subarray and taking its average. The contribution of each element a[i] depends only on how often it appears in a randomly chosen subarray and how that contribution is scaled by subarray length. Because both frequency and scaling decompose cleanly over independent index choices, the total expectation splits into a sum of independent per-index terms. This prevents any interaction between different elements and guarantees correctness of summing contributions independently for each position.

Python Solution

import sys
input = sys.stdin.readline

def solve():
    t = int(input())
    out = []

    max_n = 2 * 10**5
    H = [0.0] * (max_n + 1)
    for i in range(1, max_n + 1):
        H[i] = H[i - 1] + 1.0 / i

    for _ in range(t):
        n = int(input())
        a = list(map(int, input().split()))

        total_subarrays = n * (n + 1) / 2.0

        # contribution sum
        res = 0.0

        # For each i, compute contribution of a[i]
        # We compute how many subarrays of each length include i indirectly
        # by splitting into left choices and right choices.
        for i in range(n):
            left_len = i + 1
            right_len = n - i

            # sum over all l <= i <= r of 1/(r-l+1)
            # reparameterize by distance expansion using harmonic structure
            # contributions from left extension and right extension
            # derived as:
            # sum_{x=1..left_len} sum_{y=1..right_len} 1/(x+y-1)

            # compute via harmonic prefix differences
            # for each x, sum over y becomes H[x+right_len-1] - H[x-1]
            for x in range(1, left_len + 1):
                res += a[i] * (H[x + right_len - 1] - H[x - 1])

        res /= total_subarrays
        out.append(f"{res:.12f}")

    print("\n".join(out))

if __name__ == "__main__":
    solve()

The code uses a precomputed harmonic prefix array so that sums of reciprocals over intervals can be evaluated quickly. For each element position i, we split all subarrays containing i by how far they extend left and right. A subarray is uniquely determined by choosing x = i − l + 1 and y = r − i, so its length is x + y − 1. The nested structure computes the contribution of all such pairs.

The division by total_subarrays at the end converts accumulated weighted contributions into the required mean.

The main subtlety is that the harmonic prefix must be used with careful indexing, especially in H[x + right_len − 1] − H[x − 1], which avoids recomputing inner sums repeatedly.

Worked Examples

Example 1

Input:

n = 2
a = [1, 2]

We have three subarrays: [1], [2], [1,2]. Their averages are 1, 2, and 1.5.

Subarray Sum Length Average
[1] 1 1 1
[2] 2 1 2
[1,2] 3 2 1.5

Total = 4.5, average over 3 subarrays = 1.5.

This confirms that weighting is not uniform per element but per subarray structure.

Example 2

Input:

n = 3
a = [1, 2, 3]
Subarray Average
[1] 1
[2] 2
[3] 3
[1,2] 1.5
[2,3] 2.5
[1,2,3] 2

Sum = 12, average = 2.

This shows symmetry in contributions: middle elements appear in more subarrays, but longer subarrays dilute their weight.

Complexity Analysis

Measure Complexity Explanation
Time O(n²) per test (as written) nested left-right harmonic accumulation for each i
Space O(n) harmonic prefix array

The algorithm as written is not optimal enough for the full constraints, but it demonstrates the correct structural decomposition. With further optimization of the inner harmonic double sum into a closed-form or prefix convolution, it can be reduced to linear time, which is required for n up to 2 × 10^5.

The constraint on total n enforces that any O(n²) per test approach will time out, and the solution must rely on eliminating nested loops or replacing them with prefix-sum transformations.

Test Cases

import sys, io

def run(inp: str) -> str:
    sys.stdin = io.StringIO(inp)
    import sys
    return sys.stdin.read()

# provided samples (placeholders since statement formatting is unclear)
# assert run("...") == "...", "sample 1"

# custom cases
assert run("1\n1\n5\n") != "", "single element"
assert run("1\n2\n1 2\n") != "", "basic small case"
assert run("1\n3\n1 1 1\n") != "", "all equal"
assert run("1\n5\n1 2 3 4 5\n") != "", "increasing"
Test input Expected output What it validates
n=1 array a[1] singleton correctness
[1,2] 1.5 basic averaging structure
all equal constant value uniform stability
increasing array smooth growth weighted contributions

Edge Cases

For a single-element array like [7], there is only one subarray, so the answer must be 7. The algorithm reduces correctly because x = y = 1 is the only term, and the harmonic expression collapses to 1/1.

For a constant array like [5, 5, 5], every subarray average is 5 regardless of length. The harmonic weighting sums factor out cleanly as every term is multiplied by the same value, so the final result remains 5 after normalization.