CF 105025H - Шихан
We are working with a hidden “mountain” defined over a very large grid of size $n times m$. Somewhere on this grid there is a single special cell $(x0, y0)$, the peak.
CF 105025H - \u0428\u0438\u0445\u0430\u043d
Rating: -
Tags: -
Solve time: 55s
Verified: yes
Solution
Problem Understanding
We are working with a hidden “mountain” defined over a very large grid of size $n \times m$. Somewhere on this grid there is a single special cell $(x_0, y_0)$, the peak. Every other cell has a strictly smaller height, and the height depends only on how far the cell is from this peak. If two cells are at different distances from the peak, their heights are different, and the closer one is always higher.
The only way to obtain information is by querying a cell $(x, y)$, which returns its height as a real number. From this, we must determine the exact coordinates of the peak using as few queries as possible.
The constraints $n, m \le 10^6$ immediately rule out any strategy that inspects more than a tiny fraction of the grid. A full scan of even one row would already be too large. This forces us into an approach where every query meaningfully reduces uncertainty, typically by exploiting monotonicity or unimodality.
A subtle but important property is that the height depends only on distance to the peak, not on direction. This means that if we fix one coordinate, say $x$, and vary $y$, the function behaves like a single-peaked curve centered at $y_0$. The same holds if we fix $y$ and vary $x$. This structure is what makes the problem solvable with logarithmic search.
A naive idea would be to try random points or local search. However, since the grid is huge, random sampling has no guarantee of hitting progressively better points quickly. Even greedy neighbor climbing can take too many steps in worst-case layouts.
The key hidden edge case is when the peak is near a boundary. In such cases, local movement or naive hill climbing can walk long distances along the edge before reaching the peak, wasting queries.
Approaches
A brute-force approach would try querying every cell, tracking the maximum height seen. This is correct because the peak is the unique global maximum. However, this requires $n \cdot m$ queries, which can be up to $10^{12}$, completely infeasible.
The key observation is that although the function lives in two dimensions, it is unimodal in each coordinate when the other is fixed. If we fix $x$, then as we move along $y$, the distance to the peak decreases until $y_0$, then increases afterward. So the height along that line has a single maximum. This is exactly the structure required for ternary search.
This reduces the 2D problem into two independent 1D searches. First we locate the correct row $y_0$ by ternary searching over $y$, using any fixed $x$. Once $y_0$ is found, we repeat the same idea along the $x$-axis to locate $x_0$.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | $O(nm)$ | $O(1)$ | Too slow |
| Two-stage ternary search | $O(\log n + \log m)$ | $O(1)$ | Accepted |
Algorithm Walkthrough
We treat the interactive function as a black-box unimodal function in each coordinate.
- Fix any $x$, for convenience take $x = 1$. We now consider the function $f(y) = \text{height}(1, y)$. Because height depends only on distance to the peak, this function has a single maximum at $y = y_0$.
- Run ternary search on the interval $[1, m]$ to locate $y_0$. At each step, choose two midpoints $mid_1$ and $mid_2$, query $(1, mid_1)$ and $(1, mid_2)$, and compare heights. If the function is higher at $mid_1$, the peak lies in the left segment, otherwise it lies in the right segment. This works because unimodality guarantees no secondary maxima.
- After narrowing down, directly test the remaining few candidates to determine the exact $y_0$.
- Now fix $y = y_0$. Consider $g(x) = \text{height}(x, y_0)$, which is again unimodal with a single peak at $x_0$.
- Run ternary search over $[1, n]$ in the same way, querying $(mid, y_0)$ until the peak position $x_0$ is found.
- Output $(x_0, y_0)$ and terminate.
Why it works
The correctness relies on the fact that distance to the peak is strictly minimized at $(x_0, y_0)$, and strictly increases as we move away in any direction. Therefore, any fixed horizontal or vertical slice forms a strictly unimodal function with a single maximum. Ternary search on such a function never discards the true peak, because comparisons between two points always correctly indicate which side contains the maximum.
Python Solution
import sys
input = sys.stdin.readline
def ask(x, y):
print(f"? {x} {y}")
sys.stdout.flush()
return float(input().strip())
def ternary_search_fixed_x(x, m):
l, r = 1, m
while r - l > 3:
m1 = l + (r - l) // 3
m2 = r - (r - l) // 3
v1 = ask(x, m1)
v2 = ask(x, m2)
if v1 < v2:
l = m1
else:
r = m2
best_y = l
best_val = ask(x, l)
for y in range(l + 1, r + 1):
v = ask(x, y)
if v > best_val:
best_val = v
best_y = y
return best_y
def ternary_search_fixed_y(y, n):
l, r = 1, n
while r - l > 3:
m1 = l + (r - l) // 3
m2 = r - (r - l) // 3
v1 = ask(m1, y)
v2 = ask(m2, y)
if v1 < v2:
l = m1
else:
r = m2
best_x = l
best_val = ask(l, y)
for x in range(l + 1, r + 1):
v = ask(x, y)
if v > best_val:
best_val = v
best_x = x
return best_x
def solve():
n, m = map(int, input().split())
y0 = ternary_search_fixed_x(1, m)
x0 = ternary_search_fixed_y(y0, n)
print(f"! {x0} {y0}")
sys.stdout.flush()
if __name__ == "__main__":
solve()
The implementation separates the two coordinate searches cleanly. The helper function ask ensures flushing after every query, which is mandatory in interactive problems.
Each ternary search loop shrinks the interval based on comparing two interior points. Once the interval is small, a linear scan resolves the exact maximum safely, avoiding floating-point comparison instability in tight ranges.
Worked Examples
Consider a small conceptual grid where the peak is at $(2, 1)$.
Example trace for finding $y_0$ with fixed $x = 1$
| step | l | r | m1 | m2 | result |
|---|---|---|---|---|---|
| 1 | 1 | 3 | 1 | 2 | compare heights |
| 2 | 2 | 3 | - | - | final scan |
The search quickly identifies that $y = 1$ yields higher values than $y = 2$, shrinking the range until only the peak remains.
This confirms that unimodality along the vertical slice is sufficient to locate the correct row.
Example trace for finding $x_0$ with fixed $y = 1$
| step | l | r | m1 | m2 | result |
|---|---|---|---|---|---|
| 1 | 1 | 3 | 1 | 2 | compare heights |
| 2 | 2 | 3 | - | - | final scan |
Again, the same narrowing process isolates $x = 2$, demonstrating symmetry of the approach.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | $O(\log n + \log m)$ | Each ternary search reduces the interval by a constant factor |
| Space | $O(1)$ | Only a few variables are maintained |
The number of queries fits comfortably within typical interactive limits since each search performs only logarithmically many queries over ranges up to $10^6$.
Test Cases
import sys, io
# This is a structural template; real interaction cannot be fully simulated without a judge.
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
n, m = map(int, sys.stdin.readline().split())
# placeholder since interactive judge is required
return "interactive"
# sample placeholder
# assert run("3 2\n") == "expected"
# custom structural tests (non-interactive sanity checks)
assert run("1 1\n") == "interactive"
assert run("10 10\n") == "interactive"
assert run("1000000 1\n") == "interactive"
| Test input | Expected output | What it validates |
|---|---|---|
| 1 1 | (1,1) | minimum grid |
| 10 10 | peak position | general case |
| 1e6 1 | (1,1) | degenerate row |
| 1 1e6 | (1,1) | degenerate column |
Edge Cases
A corner case occurs when the peak lies exactly on the boundary, such as $(1, 1)$. In this case, the function is still unimodal along both axes, but the maximum is at the edge of the search interval. Ternary search still works because comparisons will always favor the boundary direction containing the peak, progressively shrinking toward it.
Another case is when $n = 1$ or $m = 1$. The problem degenerates into a pure 1D ternary search. The same logic applies, but only one phase is needed. The algorithm still behaves correctly because the unimodality assumption remains valid.
Finally, when the peak is centered, comparisons between symmetric points produce nearly identical reduction patterns, but strict inequality of heights ensures deterministic movement toward the center without oscillation.