D - 荷物運びの道 / The Path of Carrying Luggage Editorial by admin Editorial for printing
GPT 5.2 HighOverview
For each starting position \(s\), we need to find \(f(s)\), the “warehouse number where the cumulative weight first exceeds \(K\)”, and then quickly answer queries of the form \(\sum_{s=L}^{R} f(s)\) over an interval \([L,R]\).
Analysis
Key Observation
When moving east from starting position \(s\), the conditions are: - \(A_s + A_{s+1} + \cdots + A_{t-1} \le K\) - But \(A_s + \cdots + A_t > K\)
You stop at the first such \(t\) (which is \(f(s)\)).
In other words, if we let \(r\) be the “maximum reachable position while staying at or below \(K\)”, then the stopping position is:
- If \(r=N\), then \(f(s)=N\) (never exceeds the limit through the end)
- Otherwise, \(f(s)=r+1\) (the warehouse where picking up the next item causes it to exceed)
Why the Naive Solution Is Too Slow
If for each \(s\) we sum \(A_s, A_{s+1}, A_{s+2}, \ldots\) one by one, in the worst case: - \(s=1\) takes \(N\) steps - \(s=2\) takes \(N-1\) steps …
The total becomes \(O(N^2)\), which is too slow for \(N=2\times 10^5\).
How to Solve It
Since \(A_i \ge 1\), when the starting position \(s\) moves one step to the right, the “right endpoint of the valid interval” essentially never moves back to the left (it moves monotonically to the right).
Using this property, we can compute all \(f(s)\) in \(O(N)\) with the two pointers technique.
Furthermore, since queries ask for interval sums \(\sum f(s)\), we can build a prefix sum array of \(f\) and answer each query in \(O(1)\).
Algorithm
1. Compute all \(f(l)\) using the two pointers technique
We move the left endpoint \(l=1..N\) and maintain the right endpoint \(r\) and the interval sum \(ssum=\sum_{i=l}^{r} A_i\).
- Initial state: \(r=0\), \(ssum=0\) (empty interval)
- For each \(l\), do the following:
- Extend the right endpoint as far as possible
while r < N and ssum + A[r+1] <= K:
Advance \(r\) to the right as long as the total stays at or below \(K\), updating \(ssum\). - Determine the stopping warehouse number
- If \(r==N\), the limit is never exceeded, so \(f(l)=N\)
- Otherwise, picking up the next warehouse \(r+1\) would exceed the limit, so \(f(l)=r+1\)
(Note: if \(A_l > K\), then \(r\) remains at \(l-1\), so \(f(l)=l\))
- Prepare to advance to the next left endpoint
If \(r \ge l\) (the interval is non-empty), subtract \(A_l\) from \(ssum\) and advance the left endpoint by one.
- Extend the right endpoint as far as possible
Since \(r\) increases at most \(N\) times in total, the overall complexity is \(O(N)\).
Concrete Example (Illustration)
For example, with \(A=[2,3,4,1], K=5\): - \(l=1\): Can carry up to \(2+3=5\), so \(r=2\); next item \(4\) exceeds → \(f(1)=3\) - \(l=2\): After advancing left, sum is \(3\); \(3+4=7\) is not allowed → \(r=2\); next exceeds → \(f(2)=3\) - \(l=3\): From sum \(0\), can carry up to \(4+1=5\) → \(r=4=N\) → \(f(3)=4\) - \(l=4\): Can carry only \(1\) → \(r=4=N\) → \(f(4)=4\)
2. Answer queries using prefix sums of \(f\)
By building \(pref[i] = f(1)+f(2)+\cdots+f(i)\), we get: [ \sum_{s=L}^{R} f(s) = pref[R] - pref[L-1] ] which allows each query to be processed in \(O(1)\).
Complexity
- Time complexity:
- Computing \(f\) (two pointers): \(O(N)\)
- Prefix sums: \(O(N)\)
- Query processing: \(O(Q)\)
Total: \(O(N+Q)\)
- Computing \(f\) (two pointers): \(O(N)\)
- Space complexity: \(O(N)\) (arrays \(A, f, pref\))
Implementation Notes
\(A_i\) and \(K\) can be large (up to around \(10^{15}\)), so sums must be handled with 64-bit integers (in Python this is automatic).
In cases like \(A_l > K\), where “picking up that warehouse’s cargo immediately exceeds the limit”, \(r\) stays at \(l-1\), and \(f(l)=r+1=l\) is naturally handled.
Since the input can be large, fast input using
sys.stdin.buffer.read()(FastScanner) is used to keep execution time stable.Source Code
import sys
class FastScanner:
__slots__ = ("data", "n", "i")
def __init__(self):
self.data = sys.stdin.buffer.read()
self.n = len(self.data)
self.i = 0
def next_int(self):
data = self.data
n = self.n
i = self.i
while i < n and data[i] <= 32:
i += 1
num = 0
while i < n and data[i] > 32:
num = num * 10 + (data[i] - 48)
i += 1
self.i = i
return num
def main():
fs = FastScanner()
N = fs.next_int()
K = fs.next_int()
Q = fs.next_int()
A = [0] * (N + 1)
for i in range(1, N + 1):
A[i] = fs.next_int()
f = [0] * (N + 1)
r = 0
ssum = 0
for l in range(1, N + 1):
if r < l - 1:
r = l - 1
ssum = 0
while r < N and ssum + A[r + 1] <= K:
r += 1
ssum += A[r]
if r == N:
f[l] = N
else:
f[l] = r + 1 # may equal l when r == l-1
if r >= l:
ssum -= A[l]
pref = [0] * (N + 1)
for i in range(1, N + 1):
pref[i] = pref[i - 1] + f[i]
out = []
for _ in range(Q):
L = fs.next_int()
R = fs.next_int()
out.append(str(pref[R] - pref[L - 1]))
sys.stdout.write("\n".join(out))
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.2-high.
posted:
last update: