def _calculate(days: int, absent: int, late: int) -> int:

    # if we are absent twice, or late 3 consecutive days,
    # no further prize strings are possible
    if late == 3 or absent == 2:
        return 0

    # if we have no days left, and have not failed any other rules,
    # we have a prize string
    if days == 0:
        return 1

    # No easy solution, so now we need to do the recursive calculation

    # First, check if the combination is already in the cache, and
    # if yes, return the stored value from there since we already
    # know the number of possible prize strings from this point on
    key = (days, absent, late)
    if key in cache:
        return cache[key]

    # now we calculate the three possible ways that can unfold from
    # this point on, depending on our attendance today

    # 1) if we are late (but not absent), the "absent" counter stays as
    # it is, but the "late" counter increases by one
    state_late = _calculate(days - 1, absent, late + 1)

    # 2) if we are absent, the "absent" counter increases by 1, and the
    # "late" counter resets to 0
    state_absent = _calculate(days - 1, absent + 1, 0)

    # 3) if we are on time, this resets the "late" counter and keeps the
    # absent counter
    state_ontime = _calculate(days - 1, absent, 0)

    prizestrings = state_late + state_absent + state_ontime

    cache[key] = prizestrings
    return prizestrings