E - 散歩とバリケード / A Walk and Barricades 解説 by admin
Gemini 3.0 Flash (Thinking)Overview
This problem asks us to sequentially consider \(N\) movement plans for Takahashi on a number line, and maximize his final coordinate while avoiding collisions with barricades. Since the total sum of absolute movement distances is relatively small at \(5 \times 10^4\), the range of reachable coordinates is limited. By leveraging this observation, we can solve the problem using a fast dynamic programming (DP) approach with Bitset operations.
Analysis
1. Narrowing Down the Coordinate Range
Looking at the constraints, we have \(\sum |D_i| \leq 5 \times 10^4\). Since Takahashi starts at coordinate \(0\), no matter how he moves, the final coordinate \(s\) will always fall within the range \(-50000 \leq s \leq 50000\). Barricades \(X_j\) outside this range can be safely ignored.
2. Basic DP Formulation
Consider the following DP: - \(dp[i][s]:\) whether it is possible to be at coordinate \(s\) after considering the first \(i\) plans (boolean value)
For each plan \(D_i\), we check whether there is a barricade when moving from the current coordinate \(s\) to \(s + D_i\). If the move is possible, we set \(dp[i][s+D_i]\) to true. Additionally, when skipping a plan, \(dp[i][s]\) is always carried over.
However, the number of states is \(N \times (2 \times \sum |D_i|) \approx 5 \cdot 10^4 \times 10^5 = 5 \cdot 10^9\), which is too large for a naive DP to fit within the time limit.
3. Speedup Using Bitsets
By managing the information “whether coordinate \(s\) is reachable” as a bit sequence (a large integer in Python), we can update multiple coordinates simultaneously.
reachable: the \(k\)-th bit is \(1\) if coordinate \(k - S\) is reachablecan_move[d]: the corresponding bit is \(1\) if moving from coordinate \(s\) to \(s+d\) does not collide with a barricade
The transition at each step is as follows (for \(d > 0\)):
reachable |= (reachable & can_move[d]) << d
This allows us to compute transitions from all reachable coordinates at once.
4. Fast Barricade Collision Detection
When moving a distance \(d\) from coordinate \(s\), we need to quickly determine whether there is a barricade in the interval \([s, s+d]\) (or \([s+d, s]\)). This can be rephrased as: “Is coordinate \(s\) contained in the range from \(-d\) to \(0\) relative to some barricade coordinate \(X_j\)?”
Specifically, we prepare bad_bits where the bit corresponding to each barricade coordinate is set to \(1\), then take the OR (union) of bad_bits shifted by \(0, 1, \dots, |d|\) to efficiently compute “the set of coordinates from which moving would cause a collision.” This union can be computed in \(O(\log |d|)\) shift operations using a technique similar to doubling (Binary Lifting).
Algorithm
- Preparation: Set the coordinate offset \(S = \sum |D_i|\), and map coordinate \(x\) to bit position \(x + S\).
- Extract Barricades: Create a bit sequence
bad_bitsrecording the positions of barricades within the range \([-S, S]\). - Precompute Movement Feasibility: For each distinct \(D_i\) appearing in the plans, compute the set of coordinates from which movement can start without collision,
can_move[D_i].- When \(d > 0\): Take the negation of
bad_bits | (bad_bits >> 1) | ... | (bad_bits >> d). - When \(d < 0\): Take the negation of
bad_bits | (bad_bits << 1) | ... | (bad_bits << |d|).
- When \(d > 0\): Take the negation of
- Execute DP:
reachable = 1 << S(initial coordinate 0)- For each \(D_i\), update as
reachable |= (reachable & can_move[D_i]) << D_i.
- Answer: Find the highest set bit in
reachable, subtract the offset \(S\), and output the result.
Complexity
- Time Complexity: \(O\left(\frac{N \cdot S}{w} + \text{distinct}(D) \cdot \frac{S}{w} \log S\right)\)
- \(S = \sum |D_i|\), \(w\) is the word size (speedup factor from bitwise operations).
- Bitwise operations on Python’s arbitrary-precision integers are very fast, so this complexity is sufficient to pass within the time limit.
- Space Complexity: \(O(M + S)\)
- Depends on storing the barricades and maintaining the bitsets.
Implementation Notes
- Union of Bit Shifts: When computing
B | (B >> 1) | ... | (B >> k), by doubling the shift amount as \(1, 2, 4, \dots\) while taking OR, we reduce the number of operations from \(O(k)\) to \(O(\log k)\). - Python’s
int.bit_length(): This is convenient for finding the position of the leftmost (largest coordinate) \(1\) bit in thereachablebit sequence. - Handling Negative Coordinates: To handle the negative region of the number line, we must always add a fixed value (offset) to convert to non-negative indices.
# Core image of the bitset update process
for d in D:
if d > 0:
# can_move[d] is the set of coordinates s from which moving to s+d does not hit a barricade
# Take OR of the destination from applicable coordinates (<< d) and the original coordinates (skip)
reachable |= (reachable & can_move[d]) << d
else:
reachable |= (reachable & can_move[d]) >> abs(d)
Source Code
import sys
# Increase recursion depth just in case
sys.setrecursionlimit(200000)
def solve():
# Using sys.stdin.read().split() to get all input at once
input_data = sys.stdin.read().split()
if not input_data:
return
N = int(input_data[0])
M = int(input_data[1])
# D_i are the next N elements
D = [int(x) for x in input_data[2:2+N]]
# X_j are the next M elements
# M can be 0, so input_data[2+N:2+N+M] will be empty
X = [int(x) for x in input_data[2+N:2+N+M]]
# Sum of absolute values of D_i is at most 50,000
S_max = 0
for d in D:
if d > 0:
S_max += d
else:
S_max -= d
# Coordinate range of reachable s is [-S_max, S_max]
# Offset is S_max to map to non-negative bit indices [0, 2*S_max]
num_bits = 2 * S_max + 1
mask = (1 << num_bits) - 1
# bad_bits: bit k is 1 if coordinate k-S_max is a barricade
bad_bits = 0
for x in X:
if -S_max <= x <= S_max:
bad_bits |= (1 << (x + S_max))
# Pre-calculate can_move[d] for each distinct d
# can_move[d] bit s is 1 if the move d from coordinate s is valid (no barricades hit)
def get_union_shifts_right(B, k, mask):
# Returns B | (B >> 1) | ... | (B >> k)
# This uses a binary exponentiation-like trick to compute the union in O(log k) shifts
length = k + 1
res = 0
current_B = B
shift_so_far = 0
for i in range(length.bit_length()):
if (length >> i) & 1:
res |= (current_B >> shift_so_far)
shift_so_far += (1 << i)
current_B |= (current_B >> (1 << i))
current_B &= mask
res &= mask
return res
def get_union_shifts_left(B, k, mask):
# Returns B | (B << 1) | ... | (B << k)
length = k + 1
res = 0
current_B = B
shift_so_far = 0
for i in range(length.bit_length()):
if (length >> i) & 1:
res |= (current_B << shift_so_far)
shift_so_far += (1 << i)
current_B |= (current_B << (1 << i))
current_B &= mask
res &= mask
return res
can_move = {}
distinct_D = set(D)
for d in distinct_D:
if d > 0:
# Plan d > 0 from s is blocked if any X_j is in [s, s+d]
# This is equivalent to s being in [X_j-d, X_j]
# So bit s+S_max is invalid if any bit (s+S_max) is in [X_j-d+S_max, X_j+S_max]
invalid_D = get_union_shifts_right(bad_bits, d, mask)
else:
# Plan d < 0 from s is blocked if any X_j is in [s+d, s]
# This is equivalent to s being in [X_j, X_j-d] (where -d = abs(d))
# So bit s+S_max is invalid if any bit (s+S_max) is in [X_j+S_max, X_j+abs(d)+S_max]
invalid_D = get_union_shifts_left(bad_bits, -d, mask)
can_move[d] = mask & ~invalid_D
# DP with bitset
# reachable is a bitset where bit k is 1 if coordinate k-S_max is reachable
reachable = 1 << S_max
for d in D:
if d > 0:
# If no collision, we can choose to execute the plan or skip it
# Executing moves from s to s+d, skipping stays at s
# Bit s+S_max moves to (s+d)+S_max, which is a left shift by d
reachable |= (reachable & can_move[d]) << d
else:
# Executing moves from s to s+d (d is negative), which is a right shift by abs(d)
reachable |= (reachable & can_move[d]) >> (-d)
# We must mask reachable to stay within bounds, although it's naturally bounded
reachable &= mask
# The answer is the maximum coordinate s such that bit s+S_max is set
# reachable.bit_length() - 1 gives the highest bit index
print(reachable.bit_length() - 1 - S_max)
if __name__ == '__main__':
solve()
This editorial was generated by gemini-3-flash-thinking.
投稿日時:
最終更新: