Problem Description
Given a binary string s and an integer k, a substring of s is said to satisfy the k-constraint if either the number of 0’s in the substring is at most k or the number of 1’s is at most k. You are also given an array of queries, where each query is a pair [l, r] indicating a segment of s. For each query, return the number of substrings (nonempty contiguous segments) within s[l..r] that satisfy the k-constraint.
Key Insights
- Instead of iterating over all O(n²) substrings to check the constraint, notice that the property is monotonic: if a substring s[i..j] is valid then every shorter substring starting at i is also valid.
- A substring is invalid only if both counts – the number of 0’s and 1’s – are greater than k. Equivalently, it is valid if at least one of these counts is at most k.
- For each starting index i in s, we can compute the farthest ending index valid_end[i] for which every substring s[i..j] (for j from i up to valid_end[i]) satisfies the constraint. Once an index j causes both counts to exceed k, all longer substrings starting at i become invalid.
- For any query [l, r] the count of valid substrings can be computed by summing for each starting position i from l to r the number: min(valid_end[i], r) - i + 1.
- To answer many queries efficiently, we can precompute valid_end for all indices using a sliding window. Then, because each query [l, r] involves summing a function f(i, r) defined by a “min” over precomputed values, we can answer the queries offline using a Binary Indexed Tree (Fenwick tree). In particular, we split indices in [l, r] into two groups:
- Group 1: indices where valid_end[i] ≤ r. Here the contribution is F[i] = valid_end[i] − i + 1.
- Group 2: indices where valid_end[i] > r. For these indices the maximum substring ending is r, so contribution is r − i + 1.
- Finally, by precomputing a prefix-sum array over the indices (to quickly get the sum of i’s over a given range) and by processing queries in order of increasing r, we can answer each query in O(log n) time.
Space and Time Complexity
Time Complexity: O((n + Q) log n), where n is the length of the string and Q is the number of queries. Space Complexity: O(n + Q), to store the valid_end array, prefix sums, and Fenwick trees.
Solution
We first precompute valid_end for every starting index i using a sliding-window approach. For each i, we move the right pointer until adding the next character would result in both the count of 0’s and 1’s exceeding k. This gives us valid_end[i] as the largest j such that every substring s[i..j] is valid.
Now, for a query [l, r], the contribution from each starting index i (l ≤ i ≤ r) is: if valid_end[i] ≤ r, then contribution = valid_end[i] − i + 1; if valid_end[i] > r, then contribution = r − i + 1. Thus the answer for the query is sum from i = l to r of min(valid_end[i], r) − i + 1.
Since we have up to 10⁵ queries, we process the queries offline (sorted by r) and use Fenwick trees to quickly sum contributions for indices satisfying valid_end[i] ≤ current r. In parallel, we use a precomputed prefix sum over indices to calculate the sum of (r − i + 1) over the remaining indices. Fenwick trees are updated in the order of increasing valid_end[i].
Below are code solutions in Python, JavaScript, C++, and Java with detailed inline comments.