Number of Ways to Rearrange Sticks With K Sticks Visible

hard dp combinatorics

Problem

You have n sticks of distinct lengths 1..n. Line them up in a row. A stick is "visible" from the left if every stick before it is shorter (a stick is visible exactly when it is taller than all sticks to its left). Count the number of arrangements in which exactly k sticks are visible, modulo 10^9+7.

Inputn = 3, k = 2
Output3
The arrangements [1,3,2], [2,3,1], and [2,1,3] each leave exactly 2 sticks visible from the left. These are the unsigned Stirling numbers of the first kind.

def rearrange_sticks(n, k):
    MOD = 10**9 + 7
    dp = [[0] * (k + 1) for _ in range(n + 1)]
    dp[0][0] = 1
    for i in range(1, n + 1):
        for j in range(1, min(i, k) + 1):
            visible = dp[i - 1][j - 1]
            hidden = dp[i - 1][j] * (i - 1)
            dp[i][j] = (visible + hidden) % MOD
    return dp[n][k]
function rearrangeSticks(n, k) {
  const MOD = 1000000007n;
  const dp = Array.from({ length: n + 1 }, () => new Array(k + 1).fill(0n));
  dp[0][0] = 1n;
  for (let i = 1; i <= n; i++) {
    for (let j = 1; j <= Math.min(i, k); j++) {
      const visible = dp[i - 1][j - 1];
      const hidden = dp[i - 1][j] * BigInt(i - 1);
      dp[i][j] = (visible + hidden) % MOD;
    }
  }
  return Number(dp[n][k]);
}
class Solution {
    public int rearrangeSticks(int n, int k) {
        final long MOD = 1000000007L;
        long[][] dp = new long[n + 1][k + 1];
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= Math.min(i, k); j++) {
                long visible = dp[i - 1][j - 1];
                long hidden = dp[i - 1][j] * (i - 1) % MOD;
                dp[i][j] = (visible + hidden) % MOD;
            }
        }
        return (int) dp[n][k];
    }
}
int rearrangeSticks(int n, int k) {
    const long long MOD = 1000000007LL;
    vector<vector<long long>> dp(n + 1, vector<long long>(k + 1, 0));
    dp[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= min(i, k); j++) {
            long long visible = dp[i - 1][j - 1];
            long long hidden = dp[i - 1][j] * (i - 1) % MOD;
            dp[i][j] = (visible + hidden) % MOD;
        }
    }
    return (int) dp[n][k];
}
Time: O(n · k) Space: O(n · k)