E - 基地局の設置 / Installing Base Stations Editorial by admin
Gemini 3.8 Flash (High)Overview
The positions where a base station can transmit signals to resident \(i\) can be represented as the interval \([X_i - R_i, X_i + R_i]\). By restricting the candidate positions for base stations to the right endpoints of each interval and adopting the policy of “counting each interval only at the first base station that covers it”, this problem can be solved in \(O(K N^2)\) time by combining precomputation using the 2D imos method and dynamic programming (DP).
Analysis
1. Rephrasing the Problem in Terms of Intervals
The condition for resident \(i\) to receive signals from a base station at coordinate \(P\) is \(|X_i - P| \le R_i\). This is equivalent to the base station’s coordinate \(P\) being contained within the closed interval \([X_i - R_i, X_i + R_i]\). Hereafter, let \(L_i = X_i - R_i,\ R'_i = X_i + R_i\).
2. Narrowing Down Candidate Base Station Positions
Although base stations can be placed anywhere on the real line, we can see that in an optimal solution, base station positions can be restricted to match the right endpoint of some interval \(R'_i\). This is because, when sliding a base station to the right, a resident ceases to be covered only at the moment when the station passes the right endpoint of that resident’s interval. Therefore, without changing the set of covered residents, we can slide the base station to the right until it reaches a right endpoint.
Thus, the candidate coordinates for placing base stations are narrowed down to at most \(N\) values: \(\{R'_1, R'_2, \dots, R'_N\}\). Removing duplicates and sorting these in ascending order, let them be \(c_1 < c_2 < \dots < c_M\) (\(M \le N\)).
3. Establishing Rules to Avoid Duplicate Counting
When multiple base stations cover the same interval, that resident must be counted only once. When choosing base stations from left to right, we consider assigning each interval to the leftmost base station that covers it.
Let \(c_u\) be the previously selected base station, and let \(c_v\) (\(u < v\)) be the currently selected base station. The conditions for an interval \(i\) to be covered for the first time by base station \(c_v\) are as follows: - It is not covered by the previous base station \(c_u\) (or any base station to its left): \(c_u < L_i\) - It is covered by the current base station \(c_v\): \(L_i \le c_v \le R'_i\)
In summary, intervals satisfying \(c_u < L_i \le c_v \le R'_i\) constitute the new score gained by choosing \(c_v\) given that the previous base station was \(c_u\). Note that for the first base station chosen (the 1st one), there is no previous base station; by introducing a sentinel \(c_0 = -\infty\), this case can be handled uniformly with the same formula.
Algorithm
Extracting Candidate Points: Compute each resident’s interval \([L_i, R'_i]\), extract the unique values of \(R'_i\), and sort them as \(c_1 < \dots < c_M\). Also add the sentinel \(c_0 = -\infty\). If the number of base stations \(K\) is greater than \(M\), placing extra base stations at the same position or redundantly does not help, so set \(K \leftarrow \min(K, M)\).
Precomputing Costs (2D Imos Method): For each pair \((u, v)\), let
cost[u][v]be the number of intervals satisfying \(c_u < L_i \le c_v \le R'_i\). Considering the range of \((u, v)\) to which a single interval \([L_i, R'_i]\) contributes:- Condition on \(v\): The range of \(v\) satisfying \(L_i \le c_v \le R'_i\) can be found via binary search as \([v_{\text{start}}, v_{\text{end}}]\).
- Condition on \(u\): The maximum \(u\) satisfying \(c_u < L_i\) is \(u_{\text{max}} = v_{\text{start}} - 1\), so \(0 \le u \le u_{\text{max}}\).
This corresponds to a \(+1\) addition to the rectangular region \([0, u_{\text{max}}] \times [v_{\text{start}}, v_{\text{end}}]\) on the \((u, v)\) plane. By using the 2D imos method, performing the additions for all intervals can be done in \(O(N \log M + M^2)\).
- Dynamic Programming (DP):
dp[t][v]: The maximum number of residents who can receive signals when \(t\) base stations are placed and the last placed base station is \(c_v\).
Base Case:
- dp[1][v] = cost[0][v] (\(1 \le v \le M\))
Transitions: For \(t = 2, 3, \dots, K\): $\(dp[t][v] = \max_{1 \le u < v} \{ dp[t-1][u] + \text{cost}[u][v] \}\)$
Answer: The answer is the maximum value of \(\max_{1 \le v \le M} dp[t][v]\) across all steps.
Complexity
- Time Complexity:
- Extracting and sorting coordinates: \(O(N \log N)\)
- Precomputing
costusing the 2D imos method: \(O(N \log M + M^2)\) - DP updates: In each of the \(K\) steps, iterating \(v\) over \(1 \dots M\) and \(u\) over \(1 \dots v-1\) takes \(O(K M^2)\).
- Overall, it is \(O(K M^2) \le O(K N^2)\). Since \(N \le 250\), we have \(K N^2 \le 250^3 \approx 1.56 \times 10^7\), which easily runs well within the time limit.
- Space Complexity:
- Storing the
costarray and DP table consumes \(O(M^2) \le O(N^2)\) memory, which is negligible for \(N \le 250\).
- Storing the
Implementation Notes
2D Imos Method: Naively computing
cost[u][v]with a loop for each interval would take \(O(N M^2)\), but using the imos method by exploiting the fact that it is a rectangular addition optimizes it to \(O(N \log M + M^2)\).Improving Cache Efficiency: In the DP transition
dp[u] + cost[u][v], since \(v\) is fixed and \(u\) varies, the first index of the 2D arraycost[u][v]changes. In languages like Python, transposingcostbeforehand so thatcost_T[v][u] = cost[u][v]improves memory locality; accesses in the inner loop become contiguous, which significantly reduces execution time.Source Code
import sys
from bisect import bisect_left, bisect_right
def main():
input_data = sys.stdin.read().split()
if not input_data:
return
N = int(input_data[0])
K = int(input_data[1])
intervals = []
idx = 2
R_primes = []
for _ in range(N):
x = int(input_data[idx])
r = int(input_data[idx + 1])
idx += 2
L = x - r
R = x + r
intervals.append((L, R))
R_primes.append(R)
c_unique = sorted(list(set(R_primes)))
M = len(c_unique)
K = min(K, M)
c = [-10**18] + c_unique
# 2次元いもす法で cost[u][v] を前計算
# cost[u][v]: c_u < L_i <= c_v <= R_i を満たす区間の数 (0 <= u < v <= M)
diff = [[0] * (M + 2) for _ in range(M + 2)]
for L, R in intervals:
v_start = bisect_left(c, L)
if v_start > M:
continue
v_end = bisect_right(c, R) - 1
if v_start > v_end:
continue
u_max = v_start - 1
diff[0][v_start] += 1
diff[0][v_end + 1] -= 1
diff[u_max + 1][v_start] -= 1
diff[u_max + 1][v_end + 1] += 1
for u in range(M + 1):
row = diff[u]
for v in range(1, M + 1):
row[v] += row[v - 1]
for u in range(1, M + 1):
row_prev = diff[u - 1]
row_curr = diff[u]
for v in range(M + 1):
row_curr[v] += row_prev[v]
cost = diff
# 転置してメモリアクセスを高速化
cost_T = [[cost[u][v] for u in range(v)] for v in range(M + 1)]
dp = [cost[0][v] for v in range(M + 1)]
ans = max(dp[1:])
for t in range(2, K + 1):
next_dp = [0] * (M + 1)
for v in range(1, M + 1):
c_v = cost_T[v]
m = 0
for u in range(1, v):
val = dp[u] + c_v[u]
if val > m:
m = val
next_dp[v] = m
dp = next_dp
cur_max = max(dp[1:])
if cur_max > ans:
ans = cur_max
print(ans)
if __name__ == "__main__":
main()
This editorial was generated by gemini-3.8-flash-high.