CF 105198B - 21---0?
We are given a sequence of daily solve counts indirectly. The original array contains how many problems were solved on each day, but only the sum of the recent days is provided.
Rating: -
Tags: -
Solve time: 57s
Verified: yes
Solution
Problem Understanding
We are given a sequence of daily solve counts indirectly. The original array contains how many problems were solved on each day, but only the sum of the recent days is provided. For the first k days, the value represents the total number of solved problems from the beginning of the month until that day. After that, each value represents the sum of exactly the previous k days ending at that day.
The task is to recover enough information about the original daily counts to find the longest consecutive interval where every day had a positive solve count.
The constraints force us toward a linear solution. The total number of days over all test cases is at most 3 * 10^5, so an O(n) or O(n log n) method is realistic. A solution that checks every possible interval or repeatedly reconstructs sums would require around O(n^2) operations in the worst case, which is far beyond what a 2 second limit allows.
Several edge cases can break a careless implementation. When k = n, the whole array is just prefix sums, so treating every value as a normal sliding window sum gives incorrect differences. For example:
Input:
1
3 3
1 2 2
The original days are [1, 1, 0], so the answer is 2. A wrong sliding-window-only approach may fail because there are no full windows after the first k days.
Another tricky case is when the sliding sum decreases. A decrease does not directly mean the current day has zero solves, because an old positive day may leave the window. For example:
Input:
1
5 2
1 2 1 0 0
The original days are [1, 1, 0, 0, 0], so the answer is 2. Looking only at whether consecutive values increase or decrease can incorrectly classify days.
A third case is when all days are positive:
Input:
1
5 2
1 2 2 2 2
The answer is 5. A method that searches for changes in the given array rather than reconstructing the daily counts would incorrectly stop the streak early.
Approaches
The direct approach is to rebuild the original daily counts. Let the hidden array be x. For the first k days, the given values are prefix sums, so each day can be found by subtracting the previous prefix sum. After day k, the current value is a window sum. Removing the previous window and adding the new day gives the relation:
a[i] - a[i-1] = x[i] - x[i-k]
so:
x[i] = a[i] - a[i-1] + x[i-k]
This lets us compute each hidden value in constant time.
A brute-force solution could first reconstruct the full array and then test every possible streak by expanding from every starting day. This is correct because every possible interval is checked, but in the worst case it performs O(n^2) work. With n = 300000, that can mean about 90 billion operations.
The observation that each hidden day depends only on the value k positions earlier changes the problem completely. We do not need to search intervals repeatedly. While reconstructing the days, we can maintain the current streak length. Whenever the recovered value is positive, the streak grows. Whenever it is zero, the streak ends and we update the best answer. Since every day is processed once, the whole problem becomes linear.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(n²) | O(n) | Too slow |
| Optimal | O(n) | O(n) | Accepted |
Algorithm Walkthrough
- Create an array
daysthat will store the recovered number of solved problems for each day. The recurrence for later days needs the value fromkdays earlier, so keeping previous values makes the transition possible. - Recover the first
min(n, k)days using prefix sums. The first day equalsa[0]. Every later day in this prefix region isa[i] - a[i-1]. These values represent the actual daily solves because the given values are cumulative totals. - For every day after the first
kdays, compute the hidden value usinga[i] - a[i-1] + days[i-k]. The subtraction represents the old day leaving the window, and addingdays[i-k]restores the contribution that was removed. - While recovering each day, update the current streak. If the recovered value is greater than zero, increase the current streak and update the maximum. If it is zero, reset the current streak because a zero-solve day breaks consecutive solving.
- Print the maximum streak found after all days have been processed.
Why it works: the reconstruction formula exactly follows the definition of each sliding window. For the first k days, prefix differences give the only possible daily values. For later days, the difference between two adjacent window sums tells us the change caused by removing one old day and adding one new day. Since the array is guaranteed to be valid, the reconstructed values are exactly the original daily counts. The streak calculation then directly measures the longest run of positive values.
Python Solution
import sys
input = sys.stdin.readline
def solve():
t = int(input())
ans = []
for _ in range(t):
n, k = map(int, input().split())
a = list(map(int, input().split()))
days = [0] * n
best = 0
cur = 0
for i in range(n):
if i == 0:
days[i] = a[i]
elif i < k:
days[i] = a[i] - a[i - 1]
else:
days[i] = a[i] - a[i - 1] + days[i - k]
if days[i] > 0:
cur += 1
if cur > best:
best = cur
else:
cur = 0
ans.append(str(best))
print("\n".join(ans))
if __name__ == "__main__":
solve()
The array days stores the reconstructed daily solve counts. It is indexed from zero, so days[i-k] is the day that leaves the sliding window when calculating day i.
The first branch handles day zero separately because there is no previous prefix sum. The second branch covers the prefix-sum part of the input, where subtraction of adjacent values gives the exact daily count. The last branch uses the sliding-window recurrence.
Python integers are used automatically, so the large possible values of a[i] do not create overflow problems. The order of operations in the recurrence is also important: the previous window difference must be corrected by adding back the outgoing day's contribution.
Worked Examples
For the first sample:
n = 5, k = 2
a = [1, 2, 1, 4, 5]
| Day | Formula used | Recovered solves | Current streak | Maximum |
|---|---|---|---|---|
| 1 | a[0] |
1 | 1 | 1 |
| 2 | a[1]-a[0] |
1 | 2 | 2 |
| 3 | a[2]-a[1]+days[0] |
0 | 0 | 2 |
| 4 | a[3]-a[2]+days[1] |
4 | 1 | 2 |
| 5 | a[4]-a[3]+days[2] |
1 | 2 | 2 |
The reconstruction gives [1, 1, 0, 4, 1]. The zero on day three breaks the first streak, leaving the answer as 2.
For the third sample:
n = 5, k = 2
a = [1, 2, 2, 2, 2]
| Day | Formula used | Recovered solves | Current streak | Maximum |
|---|---|---|---|---|
| 1 | a[0] |
1 | 1 | 1 |
| 2 | a[1]-a[0] |
1 | 2 | 2 |
| 3 | a[2]-a[1]+days[0] |
1 | 3 | 3 |
| 4 | a[3]-a[2]+days[1] |
1 | 4 | 4 |
| 5 | a[4]-a[3]+days[2] |
1 | 5 | 5 |
Every recovered value is positive, so the streak reaches the entire month.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each day is reconstructed and processed once. |
| Space | O(n) | The recovered array is stored because future days need values from k positions earlier. |
The total n across all test cases is bounded by 3 * 10^5, so a linear pass easily fits the time limit. The memory usage is also within the 256 MB limit.
Test Cases
import sys
import io
def run(inp: str) -> str:
old_stdin = sys.stdin
sys.stdin = io.StringIO(inp)
def solve():
input = sys.stdin.readline
t = int(input())
out = []
for _ in range(t):
n, k = map(int, input().split())
a = list(map(int, input().split()))
days = [0] * n
cur = 0
best = 0
for i in range(n):
if i == 0:
days[i] = a[i]
elif i < k:
days[i] = a[i] - a[i - 1]
else:
days[i] = a[i] - a[i - 1] + days[i - k]
if days[i] > 0:
cur += 1
best = max(best, cur)
else:
cur = 0
out.append(str(best))
return "\n".join(out)
result = solve()
sys.stdin = old_stdin
return result
assert run("""3
2 2
1 2
5 2
1 2 1 4 5
5 2
1 2 2 2 2
""") == "2\n2\n5", "samples"
assert run("""1
2 1
5 0
""") == "1", "minimum k"
assert run("""1
3 3
1 2 2
""") == "2", "full prefix case"
assert run("""1
5 2
1 2 1 0 0
""") == "2", "decreasing windows"
assert run("""1
6 3
0 0 0 0 0 0
""") == "0", "all zero days"
assert run("""1
6 6
1 3 6 6 7 9
""") == "3", "large k boundary"
| Test input | Expected output | What it validates |
|---|---|---|
2 2 / 1 2 |
2 |
Smallest month and normal prefix reconstruction |
3 3 / 1 2 2 |
2 |
Case where the entire month is a prefix sum |
5 2 / 1 2 1 0 0 |
2 |
Sliding windows that decrease |
6 3 / 0 0 0 0 0 0 |
0 |
No positive day exists |
6 6 / 1 3 6 6 7 9 |
3 |
Large k and prefix boundary |
Edge Cases
When k = n, every value is a prefix sum. For:
1
3 3
1 2 2
the algorithm uses only the prefix reconstruction branch. It obtains days [1, 1, 0], updates the streak to 2, then resets after the zero. The output is 2.
When a window decreases, the algorithm does not assume the new day is zero. For:
1
5 2
1 2 1 0 0
the recovered days are [1, 1, 0, 0, 0]. The recurrence correctly accounts for the old day leaving the window, so the answer remains 2.
When every day is positive, there is no reset. For:
1
5 2
1 2 2 2 2
each reconstructed day equals 1, so the current streak grows from 1 to 5 and the final answer is 5. The algorithm handles this because it checks the reconstructed daily values rather than patterns in the input array.