1621. Number of Sets of K Non-Overlapping Line Segments
SourceBiweekly Contest 37 Q3DifficultyMediumRating2198
Description
Given n points on a 1-D plane, where the ith point (from 0 to n-1) is at x = i, find the number of ways we can draw exactly k non-overlapping line segments such that each segment covers two or more points. The endpoints of each segment must have integral coordinates. The k line segments do not have to cover all n points, and they are allowed to share endpoints.
Return the number of ways we can draw k non-overlapping line segments. Since this number can be huge, return it modulo 109 + 7.
Example 1:
Input: n = 4, k = 2
Output: 5
Explanation: The two line segments are shown in red and blue.
The image above shows the 5 different ways {(0,2),(2,3)}, {(0,1),(1,3)}, {(0,1),(2,3)}, {(1,2),(2,3)}, {(0,1),(1,2)}.
Example 2:
Input: n = 3, k = 1
Output: 3
Explanation: The 3 ways are {(0,1)}, {(0,2)}, {(1,2)}.
Example 3:
Input: n = 30, k = 7 Output: 796297179 Explanation: The total number of possible ways to draw 7 line segments is 3796297200. Taking this number modulo 109 + 7 gives us 796297179.
Constraints:
2 <= n <= 10001 <= k <= n-1
Solutions
Solution 1: Dynamic Programming
Thinking
We need exactly \(k\) non-overlapping segments on \(n\) points, and adjacent segments may share an endpoint. Enumerating both endpoints of every segment blows up even for \(n,k\le 1000\), and we would still have to keep the segments ordered and disjoint.
Segments lie on a line, so we can process points from left to right and split the state by whether the current point is the right endpoint of some segment. Let \(f[i][j]\) be the ways to place \(j\) segments on the first \(i\) points without ending at \(i\), and \(g[i][j]\) the ways that do end at \(i\).
Transitions then use only the two kinds of state at \(i-1\): if we do not end at \(i\), we inherit every placement of \(j\) segments; if we do, we either extend a segment that already ended at \(i-1\), or start a new length-\(1\) segment covering \(i-1\) and \(i\).
Let \(f[i][j]\) be the number of ways to build \(j\) segments using the first \(i\) points such that the last segment does not end at \(i\), and let \(g[i][j]\) be the number of ways where the last segment does end at \(i\). Initially \(f[1][0]=1\).
For \(f[i][j]\), the \(j\)-th segment does not end at \(i\), so the first \(i-1\) points already contain \(j\) segments:
For \(g[i][j]\), the \(j\)-th segment ends at \(i\). There are two sources, which we add together: extend a \(j\)-th segment that already ended at \(i-1\) (length greater than \(1\)), or start a new segment covering \(i-1\) and \(i\) after placing \(j-1\) segments on the first \(i-1\) points (length \(1\)). When \(j=0\) there is no right endpoint, so the second source is omitted. Thus for \(j \ge 1\):
The answer is \(f[n][k]+g[n][k]\).
The time complexity is \(O(n \times k)\), and the space complexity is \(O(n \times k)\).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
