CF 102770A - AD 2020
We need count how many calendar days inside a given inclusive interval have the property that their YYYYMMDD representation contains the three consecutive digits 202. A date is not compared as a number with the property. The actual eight-character representation matters.
Rating: -
Tags: -
Solve time: 1m 30s
Verified: yes
Solution
Problem Understanding
We need count how many calendar days inside a given inclusive interval have the property that their YYYYMMDD representation contains the three consecutive digits 202.
A date is not compared as a number with the property. The actual eight-character representation matters. For example, 22020101 contains 202 because the substring starts at the second digit of the year, while 20190202 contains it because the substring crosses from the year into the month.
The input contains up to 10^5 independent date intervals. The years are limited to 2000 through 9999, so there are only 8000 possible years. This rules out scanning every day for every query because the whole range contains almost three million days, and doing that for 10^5 cases would approach 3 * 10^11 date checks. The small fixed year range suggests preprocessing all years once and answering each query using prefix sums.
The tricky parts are the boundaries and the different places where 202 can appear. A careless solution may only check whether the year contains 202 and miss cases involving the month and day. For example, the interval 2111 02 01 to 2111 02 03 has only one valid date, 21110202, because the substring is formed by the month and day part. Another mistake is excluding the ending date. For 2020 01 01 to 2020 01 02, both dates are valid because both full strings contain 202, so the answer is 2.
Leap years also matter. For example, the interval 2200 02 28 to 2200 03 01 contains two days, not three, because 2200 is not a leap year.
Approaches
The direct solution is to iterate through every date in the interval, convert it to YYYYMMDD, and check whether "202" appears. This is easy to prove correct because every day is inspected exactly once. However, the largest possible interval spans the years 2000 to 9999, which contains about 2.9 million days. Repeating that work for 10^5 queries is far beyond the limit.
The key observation is that the calendar range is tiny compared with the number of queries. There are only 8000 possible years. We can preprocess each year by counting how many valid dates inside it contain 202, and also store prefix information inside the year.
For a query, the answer becomes:
number of valid days in years before Y2 plus number of valid days from January 1 to the ending date, minus the same value calculated for the day before the starting date.
This turns every query into a constant amount of work after preprocessing.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(number of days in range) per query | O(1) | Too slow |
| Optimal | O(1) per query after O(8000 * 366) preprocessing | O(8000 * 13 * 32) | Accepted |
Algorithm Walkthrough
- Precompute information for every year from 2000 to 9999. For each year, simulate all valid months and days, create the eight-digit date string, and count whether it contains
202.
The number of years is fixed and small, so this preprocessing is cheap and removes repeated work from the queries.
2. Store a prefix array where prefix[y] is the number of valid dates from 2000 up to the end of year y.
This allows complete years before a query boundary to be answered instantly.
3. For every year, also store cumulative counts by month and day. This lets us count only the beginning part of a year when a query ends in the middle of that year.
4. Define a function that returns the number of valid dates from 2000-01-01 to any given date.
It combines the precomputed full years with the partial year information. 5. Answer each query with:
count(end_date) - count(day_before_start_date)
Subtracting the previous day handles the inclusive interval correctly.
Why it works:
The prefix function always counts exactly the days from the fixed starting point to a requested date. For a query interval, removing everything before the first day leaves exactly the days inside the interval. Since every date is counted according to its complete YYYYMMDD representation during preprocessing, no possible occurrence of 202 is missed.
Python Solution
import sys
input = sys.stdin.readline
def leap(y):
return y % 400 == 0 or (y % 4 == 0 and y % 100 != 0)
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
year_pref = [0] * 10001
inside = {}
for y in range(2000, 10000):
cur = [[0] * 32 for _ in range(13)]
total = 0
for m in range(1, 13):
limit = days_in_month[m - 1]
if m == 2 and leap(y):
limit += 1
for d in range(1, limit + 1):
if "202" in f"{y:04d}{m:02d}{d:02d}":
total += 1
cur[m][d] = total
inside[y] = cur
year_pref[y] = year_pref[y - 1] + total
def count_to(y, m, d):
if y < 2000:
return 0
ans = year_pref[y - 1]
if m:
ans += inside[y][m][d]
return ans
def previous_day(y, m, d):
d -= 1
if d == 0:
m -= 1
if m == 0:
return y - 1, 12, 31
d = days_in_month[m - 1]
if m == 2 and leap(y):
d += 1
return y, m, d
def solve():
t = int(input())
out = []
for _ in range(t):
y1, m1, d1, y2, m2, d2 = map(int, input().split())
py, pm, pd = previous_day(y1, m1, d1)
out.append(str(count_to(y2, m2, d2) - count_to(py, pm, pd)))
print("\n".join(out))
if __name__ == "__main__":
solve()
The preprocessing loop builds two kinds of information. year_pref stores completed years, while inside[y] stores cumulative answers inside one particular year. The latter avoids iterating over months and days during every query.
The query function first takes all complete years before the target year and then adds the partial count inside the target year. The previous-day function is used because the prefix function is inclusive. Without it, the starting date would be counted twice.
Python integers do not overflow here because the total number of days in the whole supported range is only a few million. The main implementation detail to avoid is handling February correctly when moving backwards across a month boundary.
Worked Examples
For the first sample:
2111 02 01 to 2111 02 03
| Step | Date | Prefix result |
|---|---|---|
| End boundary | 2111-02-03 | Counts all valid days before and including this date |
| Start minus one day | 2111-01-31 | Removes all earlier days |
| Difference | 2111-02-01 to 2111-02-03 | 1 |
The only counted date is 21110202, which contains 202.
For the second sample:
2202 01 01 to 2202 12 31
| Step | Date | Prefix result |
|---|---|---|
| End boundary | 2202-12-31 | Includes the whole year |
| Start minus one day | 2201-12-31 | Excludes everything before 2202 |
| Difference | Entire year 2202 | 365 |
Every date in 2202 contains 202 in the year part.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(8000 * 366 + T) | Preprocessing checks every possible supported date once, then each query is constant time |
| Space | O(8000 * 13 * 32) | Stores cumulative information for each year |
The preprocessing cost is roughly three million date checks, which is small. After that, even 10^5 queries only require simple arithmetic operations.
Test Cases
import sys, io
# paste the solution above here and expose solve()
def run(inp: str) -> str:
old = sys.stdin
sys.stdin = io.StringIO(inp)
solve()
result = sys.stdout.getvalue()
sys.stdin = old
return result
assert run("""3
2111 2 1 2111 2 3
2202 1 1 2202 12 31
2000 1 1 9999 12 31
""") == "1\n365\n44294\n"
assert run("""1
2000 1 1 2000 1 1
""") == "0\n"
assert run("""1
2020 1 1 2020 1 2
""") == "2\n"
assert run("""1
2202 2 28 2202 3 1
""") == "2\n"
assert run("""1
9999 12 31 9999 12 31
""") == "0\n"
| Test input | Expected output | What it validates |
|---|---|---|
2000-01-01 to 2000-01-01 |
0 |
Minimum boundary and dates without 202 |
2020-01-01 to 2020-01-02 |
2 |
Year substring detection and inclusive ranges |
2202-02-28 to 2202-03-01 |
2 |
Leap year transition handling |
9999-12-31 to 9999-12-31 |
0 |
Maximum year boundary |
Edge Cases
A substring can cross the year boundary into the month or day. For the input 2111 02 01 2111 02 03, the algorithm does not only inspect the year. During preprocessing it checks the complete string 21110202, so the answer is correctly 1.
A year containing 202 makes every day in that year valid. For 2202 01 01 2202 12 31, the substring appears in the year digits themselves. The preprocessing value for year 2202 is the number of days in that year, which is 365, and the query returns that complete-year count.
Leap years affect the number of dates that can exist. For 2200 02 28 2200 03 01, the backward date calculation uses the Gregorian rule and recognizes that 2200 is not a leap year. February has 28 days, so no invalid February 29 is introduced.