
Problem Statement
In this problem, we are given a scenario where a student's attendance is recorded in a string format, with each character representing one of three statuses: Absent ('A'
), Late ('L'
), and Present ('P'
). For a student to be considered for an attendance award, two criteria must be satisfied: the student must have less than two days of absence and must not be late for three consecutive days. Given an integer n
, which indicates the length of the attendance record, our task is to compute how many possible attendance records of that length would make the student eligible for the award. Due to potentially large outputs, results should be returned modulo 10^9 + 7
.
Examples
Example 1
Input:
n = 2
Output:
8
Explanation:
There are 8 records with length 2 that are eligible for an award: "PP", "AP", "PA", "LP", "PL", "AL", "LA", "LL" Only "AA" is not eligible because there are 2 absences (there need to be fewer than 2).
Example 2
Input:
n = 1
Output:
3
Example 3
Input:
n = 10101
Output:
183236316
Constraints
1 <= n <= 105
Approach and Intuition
Understanding this problem requires analyzing how combinations of 'A'
, 'L'
, and 'P'
can be arranged to satisfy the given criteria for eligibility:
- Generate all possible sequences of attendance records of length
n
. - Ensure that these records have fewer than two
'A'
s. - Ensure that no sequence contains three or more consecutive
'L'
s.
The nuances in such sequence generation involve significant combinatorial calculations, especially as n
becomes large. Here's the approach:
Dynamic Programming Solution
- Base Cases: Start with initializing the counts of sequences of shorter lengths which are simpler to calculate manually or have obvious results.
- Transitional Formula: Establish a relationship where the count for each length
n
can be derived using the counts from shorter lengths. This typically involves adding a character to shorter valid sequences while maintaining the award criteria.
Modulo Operation
- Since results can be substantial due to the combinatorial explosion as
n
increases, and to avoid overflow as well as adhere to problem constraints, we use modulo10^9 + 7
at every step of our computation.
Edge Cases
- Smaller values of
n
: These are straightforward and serve as base cases for building up to largern
. - Detection of sequences ineligible for an award due to
AAA
,AAAA
(or more continous 'A's) and extensive sequences of'L'
: Incorporating mechanisms to skip such combinations saves computation.
By implementing dynamic programming efficiently, these observations can be executed with significant optimizations, leading to feasible solutions even for large values of n
, up to the upper constraint of 105
.
Solutions
- C++
- Java
- JavaScript
- Python
class Solution {
public:
int countValidSequences(int length) {
int MODULO = 1000000007;
vector<vector<int>> currentState = vector<vector<int>>(2, vector<int>(3, 0));
vector<vector<int>> nextState = vector<vector<int>>(2, vector<int>(3, 0));
currentState[0][0] = 1;
for (int len = 0; len < length; ++len) {
for (int absences = 0; absences <= 1; ++absences) {
for (int lates = 0; lates <= 2; ++lates) {
nextState[absences][0] = (nextState[absences][0] + currentState[absences][lates]) % MODULO;
if (absences < 1) {
nextState[absences + 1][0] = (nextState[absences + 1][0] + currentState[absences][lates]) % MODULO;
}
if (lates < 2) {
nextState[absences][lates + 1] = (nextState[absences][lates + 1] + currentState[absences][lates]) % MODULO;
}
}
}
currentState = nextState;
nextState = vector<vector<int>>(2, vector<int>(3, 0));
}
int result = 0;
for (int absences = 0; absences <= 1; ++absences) {
for (int lates = 0; lates <= 2; ++lates) {
result = (result + currentState[absences][lates]) % MODULO;
}
}
return result;
}
};
The given C++ code defines a solution to the problem of counting valid sequences of student attendance records based on set conditions. The records are determined valid if they contain no more than one 'A' (absence) and more than two continuous 'L' (lates).
Here's a breakdown of the approach and methodology in the code:
Initialization: Establishes a 2D vector
currentState
to keep track of the number of valid sequences for various states pertaining to absences and lates. Similarly, another 2D vectornextState
stores the count of sequences for the next day.Dynamic Programming Approach:
- For each possible sequence length (from 0 to the provided
length
), iterate through all combinations of absences (0 or 1) and lates (0 to 2). - Update
nextState
based on transitions from 'P' (present), by adding sequences that end with the corresponding absences and lates without exceeding limits. - Optionally transition to an 'A' state if current absences are less than 1, making sure not to exceed the absence limit.
- Optionally add a 'L' to the sequence if the current sequence of lates can be extended without exceeding the limit of 2 consecutive lates.
- For each possible sequence length (from 0 to the provided
Transition and State Updates:
- After iterating through all possibilities at a given sequence length, assign the
nextState
values tocurrentState
, and resetnextState
for fresh calculations for the next day (length increment).
- After iterating through all possibilities at a given sequence length, assign the
Result Calculation: Sum up all valid sequences from
currentState
after processing up to the desired sequence length.Modulo Operation: Apply a modulo operation with
MODULO = 1000000007
during calculations to prevent overflow and ensure results fit within standard integer sizes.Return Result: The final result, stored in the variable
result
, is returned from the function. It represents the count of all valid attendance sequences of the specified length. The function is designed to be efficient and robust enough to handle different input sizes, providing correct count within computational limits.
By using dynamic programming, the code efficiently calculates the number of valid sequences, ensuring quick evaluation as it reuses prior results reducing computing time significantly.
class Solution {
public int validRecord(int maxLen) {
final int MODULO = 1000000007;
// Initialize for current calculations of state
int[][] currentState = new int[2][3];
// Initialize for future calculations of state
int[][] nextState = new int[2][3];
// Starting condition: a string of length 0 without any 'A' and no 'L'.
currentState[0][0] = 1;
// Progress through each unit length
for (int length = 0; length < maxLen; ++length) {
for (int absences = 0; absences <= 1; ++absences) {
for (int lates = 0; lates <= 2; ++lates) {
// If 'P' is added, reset late count to 0
nextState[absences][0] =
(nextState[absences][0] +
currentState[absences][lates]) % MODULO;
// If 'A' is added, increment absence count
if (absences < 1) {
nextState[absences + 1][0] =
(nextState[absences + 1][0] +
currentState[absences][lates]) % MODULO;
}
// If 'L' is added, increment late count
if (lates < 2) {
nextState[absences][lates + 1] =
(nextState[absences][lates + 1] +
currentState[absences][lates]) % MODULO;
}
}
}
// Move nextState values to currentState for next round
for (int i = 0; i < currentState.length; i++) {
System.arraycopy(nextState[i], 0, currentState[i], 0, nextState[i].length);
}
// Reset nextState values
nextState = new int[2][3];
}
// Accumulate all possible valid states
int validCombinations = 0;
for (int absences = 0; absences <= 1; ++absences) {
for (int lates = 0; lates <= 2; ++lates) {
validCombinations = (validCombinations + currentState[absences][lates]) % MODULO;
}
}
return validCombinations;
}
}
The provided Java solution tackles the problem of counting valid attendance records by managing and constraining the number of absences ('A's) and consecutive late days ('L's) up to a given maximum length of record (maxLen
). Each valid record can contain:
- 'P' indicating presence
- 'A' indicating absence
- 'L' indicating late
Constraints
- You can only have at most one 'A' in the entire record.
- You cannot have more than two consecutive 'L' characters.
Solution Outline:
Define a dynamic programming approach using a 3D array structure
currentState
andnextState
, which represent the state of the record at any given length. The dimensions represent:- Absences count (0 or 1)
- Consecutive late count (0 to 2)
Initialize
currentState
for a record of length 0 without any absences or lates, represented ascurrentState[0][0] = 1
.Utilize nested loops to iterate over every possible state configuration given the constraints:
- Update
nextState
considering the addition of 'P', 'A', or 'L':- 'P' resets the late count (
lates
). - 'A' increases the absence count (
absences
), ensuring it doesn’t exceed one. - 'L' increases the late count (
lates
), ensuring it doesn’t exceed two.
- 'P' resets the late count (
- Employ modulo operation with
MODULO = 1000000007
to manage large numbers and prevent overflow.
- Update
After calculating potential configurations for a given length, transfer
nextState
values tocurrentState
to set up calculations for the next potential record length. ResetnextState
post transfer.After iterating up to the desired
maxLen
, compile the sum of all configurations fromcurrentState
that meet the valid constraints to determine the total number of valid attendance records.Return the count of valid combinations.
This implementation ensures optimal management of all valid sequences through dynamic programming, efficiently iterating through possible configurations and using modulo to maintain manageable number output.
var calculateRecord = function (n) {
const MODULO = 1000000007;
let currentStateDP = Array.from({ length: 2 }, () => Array(3).fill(0));
let nextStateDP = Array.from({ length: 2 }, () => Array(3).fill(0));
currentStateDP[0][0] = 1;
for (let length = 0; length < n; ++length) {
for (let absences = 0; absences <= 1; ++absences) {
for (let lates = 0; lates <= 2; ++lates) {
nextStateDP[absences][0] =
(nextStateDP[absences][0] + currentStateDP[absences][lates]) % MODULO;
if (absences < 1) {
nextStateDP[absences + 1][0] =
(nextStateDP[absences + 1][0] + currentStateDP[absences][lates]) % MODULO;
}
if (lates < 2) {
nextStateDP[absences][lates + 1] =
(nextStateDP[absences][lates + 1] + currentStateDP[absences][lates]) % MODULO;
}
}
}
currentStateDP = nextStateDP.map((row) => row.slice());
nextStateDP = Array.from({ length: 2 }, () => Array(3).fill(0));
}
let total = currentStateDP.flat().reduce((accum, value) => (accum + value) % MODULO, 0);
return total;
};
This JavaScript solution leverages dynamic programming to solve the problem of calculating the total number of valid student attendance records of length n
. Each record has constraints on absences ("A") not exceeding one, and consecutive lates ("L") not exceeding two.
Initialize constants and states:
- Define
MODULO
as1000000007
to ensure all calculations are performed modulo10^9 + 7
. - Create
currentStateDP
andnextStateDP
2D arrays. Here, the first dimension tracks absences while the second dimension tracks consecutive lates.
- Define
Set up base cases:
- Initialize the first attendance record with no absences and no lates, indicated by
currentStateDP[0][0] = 1
.
- Initialize the first attendance record with no absences and no lates, indicated by
Iterate through each possible record length:
For every day, consider every state (combination of absences and lates) from the current record length.
Update
nextStateDP
for every move:- Transition to the next day with one more late, unless already having two consecutive lates.
- Transition to the next day with one more absence, unless already having one.
- Move to the next day with no late count.
After each iteration, transfer the state from
nextStateDP
back tocurrentStateDP
for the next day’s calculation, and resetnextStateDP
.
Compute the total:
- Sum up all possible states in
currentStateDP
to get the total number of valid combinations moduloMODULO
.
- Sum up all possible states in
Return the total count of valid sequences, ensuring the solution remains efficient and accurately obeys the set rules about attendance recording. This approach guarantees a comprehensive check across all possible sequences of attendance records for a given day length
n
.
class Solution:
def countRewardableRecords(self, length: int) -> int:
MODULO = 1000000007
# Caching current state results for DP.
current = [[0] * 3 for _ in range(2)]
# Caching next state results for DP.
next_state = [[0] * 3 for _ in range(2)]
# Initialize starting case: empty string scenario.
current[0][0] = 1
# Process each potential employee record up to 'length'.
for _ in range(length):
for absences in range(2):
for lates in range(3):
# Adding 'P' to the sequence.
next_state[absences][0] = (
next_state[absences][0]
+ current[absences][lates]
) % MODULO
# Adding 'A' to the sequence if possible.
if absences < 1:
next_state[absences + 1][0] = (
next_state[absences + 1][0]
+ current[absences][lates]
) % MODULO
# Adding 'L' to the sequence if possible.
if lates < 2:
next_state[absences][lates + 1] = (
next_state[absences][lates + 1]
+ current[absences][lates]
) % MODULO
# Transition current to next state for next cycle.
current = [row[:] for row in next_state]
# Reset next state to zero for next iteration.
next_state = [[0] * 3 for _ in range(2)]
# Calculate the total count by summing valid states.
total_count = (
sum(
current[absences][lates]
for absences in range(2)
for lates in range(3)
)
% MODULO
)
return total_count
The presented Python solution effectively calculates how many rewardable attendance records of a given length can be formed using the letters 'P', 'L', and 'A'. Each letter represents an attendance type—'P' for present, 'L' for late, and 'A' for absent. The key constraints are: no more than one 'A' and no more than two consecutive 'L's in the record.
Here's how the implementation works:
- Use a dynamic programming (DP) approach where
current
andnext_state
arrays help manage the state transitions between different attendance records. - Initialize the DP with the base case where a record of length 0 (an empty string) is considered having one valid formation with zero absences and lates.
- Iterate over each length from 1 to the given
length
and for each possible number of absences (0 or 1) and lates (0 to 2):- Update the
next_state
for adding a 'P', incrementing the count from the same absence and late stage. - If absent less than once, update for adding an 'A', resetting lates to zero.
- If late less than twice consecutively, update for adding an 'L', incrementing the late count.
- Update the
- Transition states by copying
next_state
tocurrent
and resettingnext_state
. - After finishing the iterations, sum up all valid states' counts from the
current
configuration to compute the total number of rewardable records modulo 1,000,000,007 to handle very large numbers.
Through this method, you ensure efficient computation and state management that scales with the desired length of records. Every update is modularly reduced to keep computations within numeric limits and ensure accuracy.
No comments yet.