LeetCode 3802 - Number of Ways to Paint Sheets
The problem asks us to compute the number of ways to paint n sheets using exactly two distinct colors, subject to constraints on the maximum number of sheets each color can paint.
Difficulty: 🔴 Hard
Topics: —
Solution
Problem Understanding
The problem asks us to compute the number of ways to paint n sheets using exactly two distinct colors, subject to constraints on the maximum number of sheets each color can paint. The input consists of an integer n and an array limit of size m, where limit[i] represents the maximum sheets color i can paint. The painting must satisfy three conditions: each color must form a contiguous segment, both colors are used, and the number of sheets for each color does not exceed its corresponding limit[i].
The expected output is the total number of distinct valid arrangements modulo 10^9 + 7. Two arrangements differ if at least one sheet is painted a different color.
Constraints indicate the input size is large: n and limit[i] can go up to 10^9, and m can be up to 10^5. This precludes iterating over every sheet or every possible split naively. Edge cases include when limit[i] is smaller than the required segment length or when all limits are equal.
Approaches
Brute Force
A brute-force approach would enumerate every ordered pair of colors (i, j) and try every possible split of the n sheets into two contiguous segments x and n-x. For each split, we would check if x <= limit[i] and n-x <= limit[j]. This approach is correct but inefficient because it requires iterating over all possible splits up to n for every color pair, resulting in complexity O(m^2 * n), which is infeasible for n up to 10^9.
Optimal Approach
The key insight is that for a fixed color pair (i, j), the number of valid splits is a contiguous integer range given by:
max(1, n - limit[j]) <= x <= min(limit[i], n-1)
This range represents all valid lengths x for the first color such that the remaining n-x sheets fit within limit[j]. If min(limit[i], n-1) < max(1, n-limit[j]), there are no valid splits.
The optimal solution iterates over all ordered pairs (i, j) and sums up the count of valid splits using this formula. This reduces the complexity to O(m^2) without iterating over n.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(m^2 * n) | O(1) | Enumerates all possible splits for each pair, too slow for large n |
| Optimal | O(m^2) | O(1) | Uses arithmetic formula to count valid splits for each pair |
Algorithm Walkthrough
- Initialize a variable
MOD = 10^9 + 7to handle large results. - Initialize a variable
ans = 0to accumulate the total number of valid ways. - Iterate over all colors
ifrom0tom-1. - For each color
i, iterate over all colorsjfrom0tom-1. - Skip iterations where
i == jbecause we need two distinct colors. - Compute the lower bound of the split:
low = max(1, n - limit[j]). - Compute the upper bound of the split:
high = min(limit[i], n-1). - If
low <= high, incrementansby(high - low + 1) % MOD. - Return
ans % MOD.
Why it works: For each ordered pair (i, j), the valid segment lengths for color i form a contiguous range derived from the maximum limits. Summing the counts over all valid color pairs guarantees that all distinct arrangements are considered exactly once.
Python Solution
from typing import List
class Solution:
def numberOfWays(self, n: int, limit: List[int]) -> int:
MOD = 10**9 + 7
ans = 0
m = len(limit)
for i in range(m):
for j in range(m):
if i == j:
continue
low = max(1, n - limit[j])
high = min(limit[i], n-1)
if low <= high:
ans = (ans + high - low + 1) % MOD
return ans
The Python implementation directly follows the algorithm. Nested loops iterate over all ordered pairs of distinct colors. The range formula computes valid splits efficiently, avoiding any iteration over n. The modulo ensures correctness for large numbers.
Go Solution
func numberOfWays(n int, limit []int) int {
const MOD int = 1e9 + 7
ans := 0
m := len(limit)
for i := 0; i < m; i++ {
for j := 0; j < m; j++ {
if i == j {
continue
}
low := n - limit[j]
if low < 1 {
low = 1
}
high := limit[i]
if high > n-1 {
high = n-1
}
if low <= high {
ans = (ans + high - low + 1) % MOD
}
}
}
return ans
}
The Go solution mirrors the Python version. Bounds are carefully handled using if statements instead of max and min. Integer arithmetic and modulo are straightforward since Go uses 64-bit integers by default.
Worked Examples
Example 1
Input: n = 4, limit = [3,1,2]
Iterate over all ordered pairs (i, j):
| Pair | Low | High | Valid x values | Count |
|---|---|---|---|---|
| (0,1) | max(1,4-1)=3 | min(3,3)=3 | 3 | 1 |
| (0,2) | max(1,4-2)=2 | min(3,3)=3 | 2,3 | 2 |
| (1,0) | max(1,4-3)=1 | min(1,3)=1 | 1 | 1 |
| (1,2) | max(1,4-2)=2 | min(1,3)=1 | none | 0 |
| (2,0) | max(1,4-3)=1 | min(2,3)=2 | 1,2 | 2 |
| (2,1) | max(1,4-1)=3 | min(2,3)=2 | none | 0 |
Total = 1+2+1+0+2+0 = 6
Example 2
Input: n = 3, limit = [1,2]
| Pair | Low | High | Count |
|---|---|---|---|
| (0,1) | 1 | 1 | 1 |
| (1,0) | 2 | 2 | 1 |
Total = 2
Example 3
Input: n = 3, limit = [2,2]
| Pair | Low | High | Count |
|---|---|---|---|
| (0,1) | 1 | 2 | 2 |
| (1,0) | 1 | 2 | 2 |
Total = 4
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(m^2) | Iterate over all ordered pairs (i,j) of colors |
| Space | O(1) | Constant extra space is used for counters |
Even though n can be very large, the solution does not iterate over it directly, making the approach feasible.
Test Cases
# Basic examples
assert Solution().numberOfWays(4, [3,1,2]) == 6 # Example 1
assert Solution().numberOfWays(3, [1,2]) == 2 # Example 2
assert Solution().numberOfWays(3, [2,2]) == 4 # Example 3
# Edge cases
assert Solution().numberOfWays(2, [1,1]) == 2 # Minimum n, only 2 sheets
assert Solution().numberOfWays(10, [5,5,5]) == 30 # Multiple colors same limit
assert Solution().numberOfWays(1000000000, [1000000000,1000000000]) == 1999999998 % (10**9+7) # Large n
# No valid splits
assert Solution().numberOfWays(5, [1,1]) == 0 # Limits too small to cover n
| Test | Why |
|---|---|
| Example 1,2,3 | Validates correctness against problem examples |
| Minimum n | Ensures the algorithm works with smallest input |
| Multiple equal limits | Tests summation over multiple pairs |
| Large n | Verifies performance and modulo handling |
| No valid splits | Ensures algorithm correctly handles zero solutions |
Edge Cases
- Limits smaller than segment size: If
limit[i] < 1orlimit[j] < n-1,