D - 点検スケジュール / Inspection Schedule 解説 by admin
gemini-3.5-flash-highOverview
This problem asks us to set up several inspection intervals on a highway of total length \(T\) km, and minimize the number of event venues that overlap with the inspection intervals while satisfying the interval constraints.
By focusing on the fact that the number of event venues \(N\) is very small (\(12\) at most), we can solve this problem using Bit DP (Dynamic Programming), where the set of already overlapped event venues is represented as a bitmask.
Analysis
1. Focus on the Small Number of Event Venues
The number of event venues \(N\) is extremely small (\(0 \le N \le 12\)). When the search space of the “set of selected elements” is within \(2^N\) states (\(2^{12} = 4096\) states), Bit DP (state compression DP) becomes a powerful approach.
2. Organizing Interval Constraints and Introducing a “Virtual Starting Point”
Letting the starting points of the inspection intervals be \(s_1 \le s_2 \le \cdots \le s_p\), the interval constraints are as follows: 1. \(s_1 \le M\) 2. \(s_{j+1} - s_j \le M + K\) (\(1 \le j \le p-1\)) 3. \(T - s_p \le M + K\)
Here, let us define a virtual \(0\)-th inspection interval starting at \(s_0 = -K\). Then, the first constraint can be rewritten as follows: $\(s_1 - s_0 = s_1 - (-K) \le M + K \iff s_1 \le M\)$
This allows us to unify the first constraint (distance from the starting point) into the same format as the second constraint (distance between inspection intervals): \(s_{j+1} - s_j \le M + K\).
Similarly, the boundary condition at the end (from the last inspection interval to the end point) can be expressed as: $\(s_p \ge T - K - M\)$
3. DP (Dynamic Programming) Design
We consider a DP where we iterate through the possible starting points \(s\) of the inspection intervals from \(0\) to \(T-K\) in order, and decide whether to “adopt” each \(s\) or not.
While we maintain the “set of overlapped event venues (bitmask)” as the state, in order to perform transitions (checking the interval constraints), we need information about the starting point of the last placed inspection interval. The next starting point of an inspection interval \(s_{\text{next}}\) that can be placed must satisfy \(s_{\text{next}} - s_{\text{last}} \le M + K \iff s_{\text{last}} \ge s_{\text{next}} - M - K\) with respect to the last placed position \(s_{\text{last}}\).
Therefore, for the same overlapping status of events (bitmask), the larger the last placed position \(s_{\text{last}}\) is, the more choices we will have in the future, which is more advantageous.
Hence, we define the following DP table: - \(\text{dp}[\text{bit}]\): The maximum value of the starting point of the last placed inspection interval when the set of overlapped event venues is \(\text{bit}\) (or \(-\infty\) if unreachable).
Algorithm
Step 1: Special Case Handling
If \(T \le M\), we are allowed to have \(0\) inspection intervals (\(p=0\)). In this case, the overlap with event venues can be \(0\), so we can immediately output 0 and terminate.
Step 2: Precalculating Event Overlap Masks
For each \(s \in [0, T-K]\), we precalculate the set of event venues that overlap when the inspection interval \((s, s+K)\) is placed, as a bitmask mask[s].
The condition for the inspection interval \((s, s+K)\) and the event \((L_i, R_i)\) to overlap is \(s < R_i\) and \(L_i < s+K\).
Step 3: DP Table Initialization
The size of the DP table is \(2^N\). - Since only the virtual initial position \(s_0 = -K\) is reachable initially, we set \(\text{dp}[0] = -K\). - All other states are initialized to \(-\infty\) (unreachable).
Step 4: DP Transitions
Loop \(s\) from \(0\) to \(T-K\) in order.
For each \(s\), prepare an array nxt which is a copy of the current DP table, and perform transitions as follows:
For each state \(\text{bit}\), if \(\text{dp}[\text{bit}] \ge s - M - K\) is satisfied (i.e., we can reach \(s\) from the previous inspection interval while satisfying the interval constraint), we can place a new inspection interval at \(s\).
$\(\text{nxt}[\text{bit} \mid \text{mask}[s]] = \max(\text{nxt}[\text{bit} \mid \text{mask}[s]], s)\)$
*Note: If we do not choose \(s\), the state does not change, which is handled by initializing nxt with the contents of dp beforehand.
Step 5: Answer Aggregation
After iterating through all \(s\), we search for the answer from the states that satisfy the boundary condition at the end. Among all \(\text{bit}\) satisfying \(\text{dp}[\text{bit}] \ge T - K - M\), the minimum number of set bits (popcount) will be the answer.
Complexity
Time Complexity: \(O(T \cdot 2^N)\)
- Precalculating masks: \(O(T \cdot N)\)
- DP transitions: The outer loop runs \(T - K + 1 \le T\) times, and the inner loop runs \(2^N\) times. Thus, the overall time complexity is \(O(T \cdot 2^N)\).
- With \(T \le 1000\) and \(N \le 12\), the number of operations is at most \(1000 \times 4096 \approx 4 \times 10^6\) in the worst case, which easily runs within the time limit.
Space Complexity: \(O(T + 2^N)\)
- The size of the
maskarray is \(T - K + 1\), and the size of the DP table is \(2^N\). - The memory usage is within a few megabytes, which is very lightweight.
Implementation Points
Avoiding In-place Updates: To prevent choosing the same \(s\) multiple times in a single transition (i.e., placing multiple intervals at the same position), we manage the source array
currand the destination arraynxtseparately.Optimizing popcount: When counting the number of set bits for each bitmask in the final aggregation, we can speed up the constant factor by precomputing the popcount table for values from \(0\) to \(2^N-1\).
Source Code
import sys
def solve():
input = sys.stdin.read
data = input().split()
if not data:
return
T = int(data[0])
N = int(data[1])
K = int(data[2])
M = int(data[3])
L = []
R = []
idx = 4
for _ in range(N):
L.append(int(data[idx]))
R.append(int(data[idx+1]))
idx += 2
if T <= M:
print(0)
return
# 各 s における点検区間 (s, s+K) と重なるイベント会場のビットマスクを前計算
mask = [0] * (T - K + 1)
for s in range(T - K + 1):
m = 0
for i in range(N):
if s < R[i] and L[i] < s + K:
m |= (1 << i)
mask[s] = m
num_states = 1 << N
INF = 10**9
dp0 = [-INF] * num_states
dp1 = [-INF] * num_states
# 初期状態: 起点 (位置 -K) に bit 0 が到達可能
dp0[0] = -K
curr = dp0
nxt = dp1
for s in range(T - K + 1):
mask_s = mask[s]
limit = s - M - K
nxt[:] = curr
for bit in range(num_states):
val = curr[bit]
if val >= limit:
nbit = bit | mask_s
if s > nxt[nbit]:
nxt[nbit] = s
curr, nxt = nxt, curr
popcount = [bin(i).count('1') for i in range(num_states)]
ans = N
limit_end = T - K - M
for bit in range(num_states):
if curr[bit] >= limit_end:
if popcount[bit] < ans:
ans = popcount[bit]
print(ans)
if __name__ == '__main__':
solve()
This editorial was generated by gemini-3.5-flash-high.
投稿日時:
最終更新: