Problem Description
Given four integers – minLength, maxLength, oneGroup, and zeroGroup – count the number of binary strings whose lengths are between minLength and maxLength (inclusive) and in which every block (maximal contiguous segment) of 1’s has a length that is a multiple of oneGroup and every block of 0’s has a length that is a multiple of zeroGroup. (Note: if a digit does not appear at all, that is acceptable since 0 is considered a multiple of every number.) Return the answer modulo 10^9 + 7.
Key Insights
- The valid string is essentially formed by alternating “blocks” where each block is a sequence of identical characters.
- Each block must have a length that is a positive multiple of its given “group” value.
- A valid string can start with either a block of 0’s or a block of 1’s.
- We use dynamic programming with two states: one for strings ending in 0 and one for strings ending in 1.
- The recurrence for dp0 (ending with 0) uses contributions from dp1 values that are exactly oneGroup apart (since adding a new block of zeros must come after a block of ones) and vice‐versa.
- To avoid an O(n^2) solution (which is too slow when maxLength is 10^5), we use prefix–sum data structures, but grouped by residue classes modulo oneGroup (or zeroGroup) so that the summations over indices in arithmetic progression can be performed in O(log n) time per query.
Space and Time Complexity
Time Complexity: O(maxLength · log(maxLength)) worst-case (when oneGroup or zeroGroup are small) due to binary searches over the residue–classes. Space Complexity: O(maxLength), to store the dp arrays and the precomputed cumulative sums for each residue.
Solution
We solve the problem by doing dynamic programming over the length of the string. We maintain two arrays: • dp0[i]: number of valid strings of length i that end with a block of 0’s. • dp1[i]: number of valid strings of length i that end with a block of 1’s.
For each valid ending, the recurrence is as follows. For instance, if a valid string ending with 0 is formed by appending a block of 0’s (whose length L is a positive multiple of zeroGroup) to a valid string that ended with 1 – or directly starting the string – then
dp0[i] = (if i is a positive multiple of zeroGroup, add the “base” case) + Sum(dp1[i – m * oneGroup]) for all m such that i – m * oneGroup ≥ 0.
Similarly, dp1[i] = (if i is a positive multiple of oneGroup, add the “base” case) + Sum(dp0[i – m * zeroGroup]) for all m such that i – m * zeroGroup ≥ 0.
Because the summations are over indices that form an arithmetic progression (the difference between indices is oneGroup for dp0’s recurrence and zeroGroup for dp1’s), we can precompute and maintain cumulative sums keyed by the residue modulo oneGroup (or zeroGroup). In our implementation the idea is to store, for each residue class, the dp values along with a prefix–sum so that for each new index i we can quickly query the cumulative contribution from indices j that are congruent to i modulo oneGroup (if computing dp0) and up to i – oneGroup. (A similar idea applies when computing dp1.)
Finally, the answer is the total number of valid strings (dp0[i] + dp1[i]) for each i in [minLength, maxLength], taken modulo 10^9+7.
Important implementation details include ensuring that the “base” (i.e. a single block) is counted correctly, and taking the modulo at each step to avoid overflow.