D - 侵食される遺跡 / Eroding Ruins Editorial by admin
claude4.8opus-highOverview
This problem asks us to find the step number at which the stone block in each cell collapses. This can be modeled as a shortest path problem (Dijkstra’s algorithm) starting from the “outside of the grid,” where passing through each cell adds its durability \(C_{i,j}\) as a cost.
Analysis
Recurrence Relation for Collapse Times
Let \(t(u)\) be the step number at which a cell \(u\) collapses. By carefully tracing the mechanism of collapse, we can observe the following relationships:
For boundary cells (1st row, \(H\)-th row, 1st column, \(W\)-th column): Since they are adjacent to the outside of the grid from the initial state, they are exposed to the elements, and their durability decreases by \(1\) in every step starting from step \(1\). Therefore, their durability becomes exactly \(0\) and they collapse after \(C_u\) steps. That is: $\(t(u) = C_u\)$
For internal cells: An internal cell becomes “exposed to the elements” the moment any of its \(4\) adjacent cells collapses and becomes empty. According to the rules, the decrease in durability for a newly exposed cell begins from the next step. If an adjacent cell \(v\) collapses at step \(t(v)\), then \(u\) starts decreasing from step \(t(v)+1\) and collapses after \(C_u\) steps of decrease. Since \(u\) is exposed by the adjacent cell that collapses the earliest, we have: $\(t(u) = \min_{v \in \text{adjacent}} t(v) + C_u\)$
Here, the rule “chain-reaction collapse does not occur within the same step (decrease starts from the next step)” corresponds exactly to adding \(C_u\) directly to the collapse time of the adjacent cell.
A Unified View
If we consider the outside of the grid as a “virtual cell that collapsed at time \(0\),” the equation for boundary cells \(t(u) = C_u\) can be unified with the recurrence relation of the internal cells as “\(t(\text{outside}) = 0\) plus \(C_u\)”.
Consequently, \(t(u)\) is equal to:
The minimum cost of a path from the outside of the grid to \(u\), where the cost is the sum of the durabilities \(C\) of the visited cells.
This is exactly the shortest path problem.
Why a Naive Approach Fails
The maximum durability is \(10^9\), and the number of steps until collapse can be extremely large. Simulating the process step-by-step is far too slow to pass. By rephrasing the problem as finding the shortest path as described above, we can compute the answer efficiently without depending on the number of steps.
Algorithm
We construct a graph where each cell is a vertex, and there is a directed edge from an adjacent cell \(v \to u\) with a cost of \(C_u\) (the cost incurred when entering \(u\)). We then apply Dijkstra’s algorithm on this graph.
- For all boundary cells \(u\), set the initial distance \(\text{dist}[u] = C_u\) and push them into the priority queue (representing states reached from the outside with cost \(C_u\)).
- Perform standard Dijkstra’s algorithm: pop the vertex \(u\) with the minimum cost from the queue, and relax the distances to its adjacent cells \(v\) using \(\text{dist}[v] = \text{dist}[u] + C_v\).
- The computed \(\text{dist}[u]\) will be the collapse step number \(t(u)\) for that cell.
Each query can be answered in \(O(1)\) time simply by referencing the precomputed \(\text{dist}\) array.
Complexity
Let \(N = H \times W\) be the number of vertices. Since each vertex has at most \(4\) edges, the number of edges is \(O(N)\).
- Time Complexity: \(O(N \log N + Q)\)
- Space Complexity: \(O(N)\)
Since \(N \le 500 \times 500 = 250000\) and \(Q \le 10^5\), this approach runs well within the time limit.
Implementation Points
Flattening 2D coordinates to 1D: Representing cell \((i, j)\) as a 1D index
i*W + jmakes array access and heap operations faster and simpler. The reverse conversion can be done usingdivmod(u, W).Boundary Check: A cell is a boundary cell if
i == 0 or i == H-1 or j == 0 or j == W-1. We push these cells into the heap in the initial state.Lazy Deletion in Dijkstra: If the distance
dpopped from the heap is strictly greater than the currentdist[u](d > dist[u]), it is an outdated state that has already been updated, so we skip it. This ensures the complexity bound is maintained.When moving to adjacent cells, check the boundaries using conditions like
i > 0,i < H-1,j > 0,j < W-1to avoid going out of the grid.Source Code
import sys, heapq
def main():
data = sys.stdin.buffer.read().split()
idx = 0
H = int(data[idx]); idx += 1
W = int(data[idx]); idx += 1
N = H * W
C = [0]*N
for i in range(N):
C[i] = int(data[idx]); idx += 1
INF = float('inf')
dist = [INF]*N
heap = []
push = heapq.heappush
pop = heapq.heappop
# 境界マスを初期化
for i in range(H):
base = i*W
on_row_edge = (i == 0 or i == H-1)
for j in range(W):
if on_row_edge or j == 0 or j == W-1:
p = base + j
c = C[p]
dist[p] = c
push(heap, (c, p))
while heap:
d, u = pop(heap)
if d > dist[u]:
continue
i, j = divmod(u, W)
if i > 0:
v = u - W; nd = d + C[v]
if nd < dist[v]:
dist[v] = nd; push(heap, (nd, v))
if i < H-1:
v = u + W; nd = d + C[v]
if nd < dist[v]:
dist[v] = nd; push(heap, (nd, v))
if j > 0:
v = u - 1; nd = d + C[v]
if nd < dist[v]:
dist[v] = nd; push(heap, (nd, v))
if j < W-1:
v = u + 1; nd = d + C[v]
if nd < dist[v]:
dist[v] = nd; push(heap, (nd, v))
Q = int(data[idx]); idx += 1
out = []
for _ in range(Q):
r = int(data[idx]); k = int(data[idx+1]); idx += 2
out.append(dist[(r-1)*W + (k-1)])
sys.stdout.write('\n'.join(map(str, out)))
sys.stdout.write('\n')
main()
This editorial was generated by claude4.8opus-high.
posted:
last update: