D - 連続練習日数 / Consecutive Practice Days Editorial by admin
Qwen3-Coder-480BOverview
Given the training intensity over \(N\) days, count the number of intervals of \(K\) or more consecutive days whose total is at least \(M\).
Analysis
In this problem, for every interval \((l, r)\), we need to determine whether it has “length at least \(K\)” and “sum at least \(M\)”.
Naive Approach and Its Issues
The first idea that comes to mind is to try all possible intervals \((l, r)\). If we compute the sum from scratch for each interval, the time complexity becomes \(O(N^3)\), which is far too slow since \(N\) can be up to \(2 \times 10^5\).
For example, consider the following input:
N=5, K=2, M=5
A = [2, 2, 2, 2, 2]
In this case, intervals such as \((l,r)=(1,2), (1,3), ..., (4,5)\) are all candidates, but naively computing the sum for each one would take too much time.
Improvement: Prefix Sums and Binary Search
The standard technique for efficiently computing interval sums is prefix sums. By preparing a prefix sum array \(prefix\), the sum of any interval \([l, r]\) can be computed in \(O(1)\):
\[ \text{sum}(l, r) = prefix[r] - prefix[l-1] \]
Next, we need to efficiently count the “intervals that satisfy the conditions.” For a fixed left endpoint \(l\), if we can find the first right endpoint \(r\) where the interval sum becomes at least \(M\) as we increase \(r\), then all subsequent values of \(r\) will also satisfy the condition.
Specifically, for each \(l\), we perform the following operations: 1. Compute the first right endpoint that satisfies the minimum interval length \(K\): \(min\_r = l + K - 1\). 2. Within the range from this point to \(N\), use binary search to find the first \(r\) where the interval sum is at least \(M\). 3. If such an \(r\) exists, include everything from that point to the end in the count.
By doing this, we avoid recomputing the sum for each interval and also avoid brute-force enumeration, allowing us to find the answer efficiently.
Algorithm
- Build the prefix sum array \(prefix\) (of length \(N+1\)).
- For each left endpoint \(l = 1, 2, ..., N\), do the following:
- Compute the first right endpoint satisfying the minimum interval length \(K\): \(min\_r = l + K - 1\).
- If \(min\_r > N\), skip.
- Use binary search to find the smallest right endpoint \(valid\_r\) where the interval sum is at least \(M\).
- If such a \(valid\_r\) exists, all right endpoints from \(valid\_r\) to \(N\) satisfy the condition, so add \(N - valid\_r + 1\) to the count.
Complexity
- Time complexity: \(O(N \log N)\)
- Binary search is performed for each \(l\), so the overall complexity is \(O(N \log N)\).
- Space complexity: \(O(N)\)
- The prefix sum array has size \(N+1\).
Implementation Notes
Adding \(0\) at the beginning of the prefix sum array simplifies index handling.
In the binary search, since we are looking for “the first position that satisfies the condition,” we update with
right = mid - 1.To safely reference
prefix[l-1]even when \(l=1\), manage the prefix array with shifted indices.Source Code
import sys
from itertools import accumulate
def main():
input = sys.stdin.read
data = input().split()
N = int(data[0])
K = int(data[1])
M = int(data[2])
A = list(map(int, data[3:3+N]))
# 累積和を計算
prefix = [0] + list(accumulate(A))
count = 0
# 各開始位置 l について、条件を満たす終了位置 r の個数を数える
for l in range(1, N+1):
# 区間長が K 以上である最小の r
min_r = l + K - 1
if min_r > N:
continue
# 二分探索で条件を満たす最小の r を求める
left = min_r
right = N
valid_r = -1
while left <= right:
mid = (left + right) // 2
s = prefix[mid] - prefix[l-1]
if s >= M:
valid_r = mid
right = mid - 1
else:
left = mid + 1
# 条件を満たす r が存在すれば、それ以降すべての r も条件を満たす
if valid_r != -1:
count += N - valid_r + 1
print(count)
if __name__ == "__main__":
main()
This editorial was generated by qwen3-coder-480b.
posted:
last update: