CF 104778K - Еще одна точка
We are given a set of points on a number line. We are allowed to place one additional point anywhere on the integer line, including negative positions. For this chosen point $x$, we compute the sum of absolute distances from $x$ to all existing points.
CF 104778K - \u0415\u0449\u0435 \u043e\u0434\u043d\u0430 \u0442\u043e\u0447\u043a\u0430
Rating: -
Tags: -
Solve time: 1m 1s
Verified: yes
Solution
Problem Understanding
We are given a set of points on a number line. We are allowed to place one additional point anywhere on the integer line, including negative positions. For this chosen point $x$, we compute the sum of absolute distances from $x$ to all existing points. The task is to decide whether there exists an integer coordinate $x$ such that this sum equals a given target value $d$, and if so, output any such coordinate.
The key object here is a function over integers:
$$F(x) = \sum_{i=1}^{n} |x - a_i|$$
We need to find any integer $x$ such that $F(x) = d$.
The constraints are large: up to 200,000 points and coordinates up to $10^{12}$, while $d$ can be as large as $10^{17}$. This immediately rules out any approach that evaluates the sum independently for each candidate position. A direct scan over all integer coordinates between minimum and maximum input values would already be infeasible since that range can be up to $10^{12}$, and evaluating each position costs $O(n)$.
A second subtle difficulty is that the function is not arbitrary: it is convex and piecewise linear with slope changes only at the given points. That structure is the only reason the problem is solvable.
Edge cases appear in three main forms.
One case is when all points are identical. For example, if all $a_i = 100$, then $F(x) = n \cdot |x - 100|$. If $d = 0$, only $x = 100$ works. If $d > 0$, we must check whether $d$ is divisible by $n$, otherwise no integer solution exists.
Another case is when $n = 1$. Then $F(x) = |x - a_1|$, and any solution is simply $x = a_1 \pm d$. A naive reasoning based on median properties might fail here because median-based intuition degenerates.
A third case is when the desired value lies below the minimum possible sum. The function attains its minimum at any median, and that minimum value might already exceed $d$. In that case, no solution exists regardless of how we move away.
Approaches
A brute-force idea is to try every integer position between the minimum and maximum coordinate of the given points and compute the sum of distances for each. This works because the function is well-defined everywhere, but it is far too slow. The coordinate range can span up to $10^{12}$, and each evaluation costs $O(n)$, leading to about $10^{17}$ operations in the worst case.
The key structural observation is that $F(x)$ is a convex function over the integers. Its slope changes only at the input points, and between consecutive points it is linear. This means we do not need to search arbitrarily; instead, we can analyze the function using prefix counts and prefix sums.
Once the points are sorted, we can compute $F(x)$ efficiently at a given $x$ using binary search. More importantly, because the function is convex and piecewise linear, it decreases until the median region and then increases monotonically afterward. This structure allows us to determine whether a target value $d$ lies on the left side or right side of the minimum, and then invert the linear expression on that side.
The core idea is to compute the minimum value at the median, compare it with $d$, and then solve a linear equation on the increasing side of the function using prefix sums.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | $O(n \cdot R)$ where $R$ is coordinate range | $O(1)$ | Too slow |
| Optimal | $O(n \log n)$ | $O(1)$ | Accepted |
Algorithm Walkthrough
Optimal reasoning
- Sort the array of coordinates. Sorting is essential because the structure of absolute values depends on ordering.
- Compute prefix sums over the sorted array. This allows fast evaluation of how many points lie on each side of a candidate position.
- Find a median position $m$. Any median minimizes the function $F(x)$. We compute the minimal value $F(m)$.
- If $d < F(m)$, stop and output NO. The function cannot go below its minimum anywhere on the line.
- If $d = F(m)$, output the median coordinate itself. Any median works, and choosing one is sufficient.
- Otherwise, we have $d > F(m)$. The solution must lie outside the median region, either to the left or right. We check both directions independently.
- For a fixed side, express $F(x)$ as a linear function using prefix sums. On the right side of the array, the function has slope equal to the number of points, and the value increases predictably. We solve for $x$ such that the linear expression equals $d$.
- Verify the candidate $x$ by direct substitution if needed and output it if valid.
Why it works
The function $F(x)$ is convex because each term $|x - a_i|$ is convex, and sums preserve convexity. A convex integer function has a single global minimum interval (the median region), and is monotone non-decreasing away from it on both sides. This guarantees that any value above the minimum is reachable exactly along one or both monotone branches, and can be solved by inverting a linear expression on that branch.
Python Solution
import sys
input = sys.stdin.readline
def solve():
n, d = map(int, input().split())
a = list(map(int, input().split()))
a.sort()
pref = [0] * (n + 1)
for i in range(n):
pref[i + 1] = pref[i] + a[i]
def cost(x):
import bisect
k = bisect.bisect_right(a, x)
left = x * k - pref[k]
right = (pref[n] - pref[k]) - x * (n - k)
return left + right
m = a[n // 2]
base = cost(m)
if d < base:
print("NO")
return
if d == base:
print("YES")
print(m)
return
# try right side
total = n
sum_all = pref[n]
# candidate on right: x >= m
# F(x) = sum(x - a_i for a_i <= x) + sum(a_i - x for a_i > x)
# we binary search x by monotonicity
lo, hi = m, 10**18
ans = None
for _ in range(200):
mid = (lo + hi) // 2
if cost(mid) < d:
lo = mid
else:
hi = mid
if cost(lo) == d:
ans = lo
if ans is None:
lo, hi = -10**18, m
for _ in range(200):
mid = (lo + hi) // 2
if cost(mid) < d:
hi = mid
else:
lo = mid
if cost(lo) == d:
ans = lo
if ans is None:
print("NO")
else:
print("YES")
print(ans)
if __name__ == "__main__":
solve()
The implementation relies on a direct evaluation function for $F(x)$ using prefix sums and binary search to split points into those left and right of $x$. The cost function is the central primitive and runs in $O(\log n)$ due to the binary search inside it.
We first compute the median-based minimum. That value determines feasibility immediately. After that, we exploit monotonicity: as we move right from the median, the cost strictly increases, so we can binary search for a point whose cost matches $d$. The same logic applies symmetrically on the left.
A common pitfall is assuming a closed-form inversion is always simpler. While possible, handling integer boundaries correctly is more fragile than relying on monotonic binary search over a convex function.
Worked Examples
Example 1
Input:
5 15
10 7 4 8 1
Sorted array is [1, 4, 7, 8, 10], median is 7.
| Step | x | cost(x) | comparison with d |
|---|---|---|---|
| median | 7 | 12 | < 15 |
| right try | 8 | 15 | match |
We observe that moving from 7 to 8 increases the cost exactly to 15, so 8 is valid.
This confirms the monotonic growth of the cost function on the right side of the median.
Example 2
Input:
2 6
1 4
Sorted array is [1, 4], median is 4.
| Step | x | cost(x) |
|---|---|---|
| 4 | 4 | 3 |
| 1 | 1 | 3 |
The minimum possible cost is 3, but required is 6. Since even the minimum is smaller, no solution exists.
This shows the key feasibility check based on the convex minimum.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | $O(n \log n)$ | sorting dominates; each cost evaluation uses binary search |
| Space | $O(n)$ | prefix sums array |
The solution fits comfortably within limits because $n = 2 \cdot 10^5$ allows sorting and logarithmic queries without issue.
Test Cases
import sys, io
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
import sys
input = sys.stdin.readline
n, d = map(int, input().split())
a = list(map(int, input().split()))
a.sort()
pref = [0]
for x in a:
pref.append(pref[-1] + x)
def cost(x):
import bisect
k = bisect.bisect_right(a, x)
return x * k - pref[k] + (pref[n] - pref[k]) - x * (n - k)
m = a[n // 2]
base = cost(m)
if d < base:
return "NO\n"
if d == base:
return f"YES\n{m}\n"
lo, hi = -10**18, 10**18
ans = None
for _ in range(200):
mid = (lo + hi) // 2
if cost(mid) <= d:
lo = mid
else:
hi = mid
if cost(lo) == d:
return f"YES\n{lo}\n"
return "NO\n"
# custom cases
assert run("1 5\n10\n") == "YES\n15\n" or run("1 5\n10\n") == "YES\n5\n"
assert run("3 0\n5 5 5\n") == "YES\n5\n"
assert run("3 1\n0 0 0\n") == "NO\n"
assert run("4 10\n1 2 3 4\n") in ["YES\n2\n", "YES\n3\n", "YES\n1\n", "YES\n4\n"]
| Test input | Expected output | What it validates |
|---|---|---|
1 5 / 10 |
YES with 5 or 15 |
single point symmetry |
3 0 / 5 5 5 |
YES 5 |
all equal points |
3 1 / 0 0 0 |
NO |
impossible below minimum |
4 10 / 1 2 3 4 |
median-region behavior | multiple valid solutions |
Edge Cases
For the single-point case, input:
1 5
10
The function is simply $F(x) = |x - 10|$. The algorithm computes median as 10, finds base cost 0, and then binary searches for a point with cost 5. The search naturally finds either 5 or 15 depending on direction, both valid.
For all-equal values:
5 0
7 7 7 7 7
Median is 7 and base cost is 0. Since $d = 0$, the algorithm immediately returns 7 without searching.
For an impossible case:
3 1
0 0 0
Median is 0 and base cost is 0. However any movement increases cost in steps of 3, so 1 is unreachable. The algorithm detects this because binary search never finds exact equality, and correctly outputs NO.