D - 侵食される遺跡 / Eroding Ruins 解説 by admin
gpt-5.5-highOverview
This problem asks us to find the step in which the block in each cell collapses.
The key insight is that the collapse time can be thought of as the “minimum sum of the durability values of the cells along a path from the outer boundary to that cell.”
Analysis
Let \(T(v)\) be the step at which cell \(v\) collapses.
First, the boundary cells are exposed to the elements from the very beginning.
Therefore, a boundary cell with durability \(C_v\) will decrease by \(1\) in each step starting from step \(1\), and will collapse at exactly step \(C_v\).
That is, for boundary cells:
\[ T(v) = C_v \]
Next, let’s consider the inner cells.
Suppose an adjacent cell \(u\) collapses at step \(T(u)\).
Then, cell \(v\) will be exposed to the elements starting from the next step, \(T(u)+1\).
Since its durability is \(C_v\), it will decrease \(C_v\) times from that point and then collapse, so the collapse step will be:
\[ T(u) + C_v \]
Therefore, cell \(v\) will be eroded by the adjacent cell that collapses the earliest, so we can express it as:
\[ T(v) = C_v + \min_{u \in \text{adjacent cells}} T(u) \]
Looking at this from a different perspective, this transforms the problem into:
- Treat the boundary cells as the starting points.
- The cost to enter a cell is its durability value \(C_{i,j}\).
- Find the shortest distance to each cell.
In other words, the collapse step of cell \(v\) is:
\[ T(v) = \min_{\text{path from boundary to } v} \sum_{\text{cell } x \text{ on the path}} C_x \]
For example, if you reach a target cell from a boundary cell by passing through cells with durabilities \(3, 5, 2\) in order, the target cell will collapse at step:
\[ 3 + 5 + 2 = 10 \]
Naive Simulation is Too Slow
If we simulate the process by checking the cells exposed to the elements and reducing their durability at each step, it will take too much time because the maximum durability can be up to \(10^9\).
Furthermore, since the maximum collapse step is the sum of durabilities along the path, it can be up to around:
\[ 500 \times 500 \times 10^9 \]
A step-by-step simulation will not run in time.
Therefore, we model this as a shortest path problem on a weighted graph and solve it using Dijkstra’s algorithm.
Algorithm
We consider each cell of the grid as a vertex.
Edges are directed between adjacent cells (up, down, left, right). The cost of moving from cell \(v\) to an adjacent cell \(u\) is the durability of the destination cell, \(C_u\).
Since the boundary cells are exposed to the elements from the beginning, their initial distance is set to their own durability values.
The procedure is as follows:
- Initialize the collapse step
distfor each cell to infinity. - For each boundary cell, set
dist = Cand push it into the priority queue. - Perform Dijkstra’s algorithm:
- Pop the cell with the smallest collapse step.
- For each cell adjacent to it, update its value with:
\[ \text{New Candidate} = \text{Collapse Step of Current Cell} + \text{Durability of Adjacent Cell} \]
- Output the
distof the cells specified in the queries.
This dist will be the step number at which the cell collapses.
Complexity
Let \(N = H \times W\).
The number of edges in the grid is at most around \(4N\). Since we use Dijkstra’s algorithm:
- Time Complexity: \(O(HW \log(HW) + Q)\)
- Space Complexity: \(O(HW + Q)\)
Key Implementation Points
The cell \((r, c)\) is flattened to a 1D index using
idx = r * W + c.The priority queue stores pairs of
(collapse step, cell index).In Dijkstra’s algorithm, outdated information can remain in the queue. Therefore, if the popped value does not match the current
dist, ignore it.When updating adjacent cells, add
+ C[adjacent cell]instead of+1.- This is because erosion starts from the step after the adjacent cell collapses, and it takes steps equal to the durability of the current cell to collapse.
In the code, an optimization is included to terminate Dijkstra’s algorithm early once all inner cells specified in the queries have been determined. The answers for boundary cells are already determined as
Cfrom the start.Source Code
import sys
from heapq import heappush, heappop, heapify
def main():
data = list(map(int, sys.stdin.buffer.read().split()))
p = 0
H = data[p]
W = data[p + 1]
p += 2
N = H * W
C = data[p:p + N]
p += N
Q = data[p]
p += 1
queries = [0] * Q
target = bytearray(N)
remain = 0
bottom = H - 1
right = W - 1
for qi in range(Q):
r = data[p] - 1
c = data[p + 1] - 1
p += 2
idx = r * W + c
queries[qi] = idx
if r != 0 and r != bottom and c != 0 and c != right:
if target[idx] == 0:
target[idx] = 1
remain += 1
del data
if remain == 0:
sys.stdout.write("\n".join([str(C[idx]) for idx in queries]))
return
INF = 10 ** 18
dist = [INF] * N
heap = []
# top row
for j in range(W):
v = C[j]
dist[j] = v
heap.append((v, j))
# bottom row
base = N - W
for j in range(base, N):
v = C[j]
dist[j] = v
heap.append((v, j))
# left and right columns excluding corners
last_col = W - 1
for idx in range(W, base, W):
v = C[idx]
dist[idx] = v
heap.append((v, idx))
idx2 = idx + last_col
v = C[idx2]
dist[idx2] = v
heap.append((v, idx2))
heapify(heap)
pop = heappop
push = heappush
c_arr = C
d_arr = dist
tgt = target
width = W
total = N
lower_limit = N - W
rem = remain
while heap:
d, v = pop(heap)
if d != d_arr[v]:
continue
if tgt[v]:
tgt[v] = 0
rem -= 1
if rem == 0:
break
if v >= width:
u = v - width
nd = d + c_arr[u]
if nd < d_arr[u]:
d_arr[u] = nd
push(heap, (nd, u))
if v < lower_limit:
u = v + width
nd = d + c_arr[u]
if nd < d_arr[u]:
d_arr[u] = nd
push(heap, (nd, u))
col = v % width
if col:
u = v - 1
nd = d + c_arr[u]
if nd < d_arr[u]:
d_arr[u] = nd
push(heap, (nd, u))
if col != last_col:
u = v + 1
nd = d + c_arr[u]
if nd < d_arr[u]:
d_arr[u] = nd
push(heap, (nd, u))
sys.stdout.write("\n".join([str(dist[idx]) for idx in queries]))
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.5-high.
投稿日時:
最終更新: