D - 荷物運びの道 / The Path of Carrying Luggage Editorial by admin
Qwen3-Coder-480BOverview
Precompute the endpoint of carrying luggage from each starting point, then answer range sum queries efficiently.
Analysis
In this problem, for each starting point \(s\), we need to determine where Takahashi stops (\(f(s)\)), and then for multiple intervals \([L_j, R_j]\), compute \(f(L_j) + \cdots + f(R_j)\).
If we naively simulate for each query, the worst case requires \(O(N)\) computation per query, resulting in \(O(QN)\) overall, which will TLE given the large constraints.
Therefore, if we precompute \(f(s)\) for each starting point \(s\), we can answer range sum queries efficiently.
Let’s consider how to compute \(f(s)\). This is “the point where the cumulative weight first exceeds \(K\) when traveling east from starting point \(s\),” which is equivalent to finding “the smallest \(t\) such that \(acc[t] - acc[s-1] > K\) on the prefix sum array.”
This can be computed efficiently using binary search on the prefix sum array.
Algorithm
- Read the input and compute the prefix sum \(acc[0..N]\) (where \(acc[0] = 0\)).
- For each starting point \(s = 1, 2, ..., N\), compute \(f(s)\) as follows:
- \(target = acc[s-1] + K\)
- Use binary search to find the first index \(t\) in \(acc[s..N]\) that exceeds \(target\).
- If no such \(t\) exists, \(f(s) = N\)
- Build a prefix sum array \(f\_prefix\) over \(f[1..N]\).
- For each query \([L_j, R_j]\), output \(f\_prefix[R_j] - f\_prefix[L_j - 1]\).
Complexity
- Time complexity: \(O(N \log N + Q)\)
- Space complexity: \(O(N)\)
Implementation Notes
Using prefix sums allows fast computation of partial sums.
Binary search is used to compute each \(f(s)\) in \(O(\log N)\).
Answering range sum queries is possible in \(O(1)\) using the prefix sum table.
In Python,
bisect.bisect_rightis convenient as it supports specifying a range.Source Code
import sys
from itertools import accumulate
def main():
import sys
input = sys.stdin.read
data = input().split()
idx = 0
N = int(data[idx])
idx += 1
K = int(data[idx])
idx += 1
Q = int(data[idx])
idx += 1
A = [int(data[idx + i]) for i in range(N)]
idx += N
# 累積和を計算
acc = [0] + list(accumulate(A))
# f(s) を前計算する
# f(s) は最小の t >= s 使得 acc[t] - acc[s-1] > K
# つまり acc[t] > acc[s-1] + K
# 特别地,如果不存在这样的 t,则 f(s) = N
# 使用二分查找来计算每个 f(s)
f = [0] * (N + 1) # f[s] 对应起点为 s 的结果(s 从1开始)
import bisect
# 对于每个 s (1-based), 找到最小的 t (>=s) 使得 acc[t] > acc[s-1] + K
for s in range(1, N+1):
target = acc[s-1] + K
# 在 acc[s:] 中找到第一个大于 target 的索引
# bisect_right 返回插入点,即第一个大于 target 的位置
pos = bisect.bisect_right(acc, target, s)
if pos > N:
f[s] = N
else:
f[s] = pos
# 构建 f 的前缀和以便快速回答区间和查询
f_prefix = [0] * (N + 2)
for i in range(1, N+1):
f_prefix[i] = f_prefix[i-1] + f[i]
results = []
for _ in range(Q):
L = int(data[idx])
idx += 1
R = int(data[idx])
idx += 1
res = f_prefix[R] - f_prefix[L-1]
results.append(str(res))
print('\n'.join(results))
if __name__ == "__main__":
main()
This editorial was generated by qwen3-coder-480b.
posted:
last update: