Official

D - 荷物運びの道 / The Path of Carrying Luggage Editorial by admin

Qwen3-Coder-480B

Overview

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

  1. Read the input and compute the prefix sum \(acc[0..N]\) (where \(acc[0] = 0\)).
  2. 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\)
  3. Build a prefix sum array \(f\_prefix\) over \(f[1..N]\).
  4. 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_right is 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: