1866. 恰有 K 根木棍可以看到的排列数目

2021/05/23 leetcode 共 1178 字,约 4 分钟

title

problem link

有 n 根长度互不相同的木棍,长度为从 1 到 n 的整数。请你将这些木棍排成一排,并满足从左侧 可以看到 恰好 k 根木棍。从左侧 可以看到 木棍的前提是这个木棍的 左侧 不存在比它 更长的 木棍。

  • 例如,如果木棍排列为 [***1***,***3***,2,***5***,4] ,那么从左侧可以看到的就是长度分别为 1、3 、5 的木棍。

给你 n 和 k ,返回符合题目要求的排列 数目 。由于答案可能很大,请返回对 109 + 7 取余 的结果。

示例 1:

输入:n = 3, k = 2
输出:3
解释:[1,3,2], [2,3,1] 和 [2,1,3] 是仅有的能满足恰好 2 根木棍可以看到的排列。
可以看到的木棍已经用粗体+斜体标识。

示例 2:

输入:n = 5, k = 5
输出:1
解释:[1,2,3,4,5] 是唯一一种能满足全部 5 根木棍可以看到的排列。
可以看到的木棍已经用粗体+斜体标识。

示例 3:

输入:n = 20, k = 11
输出:647427950
解释:总共有 647427950 (mod 109 + 7) 种能满足恰好有 11 根木棍可以看到的排列。

提示:

  • 1 <= n <= 1000
  • 1 <= k <= n

solution

思路与算法

我们用 f(i, j)f(i,j) 表示长度为 1, 2, \cdots, i1,2,⋯,i 的木棍且可以可以看到其中的 jj 根木棍的方案数。

class Solution:
    def rearrangeSticks(self, n: int, k: int) -> int:
        if not n and not k: return 1
        if not n or not k: return 0
        import functools
        mod = 10 ** 9 + 7
        memo = [[-1] *(k+1) for _ in range(n+1)]
        def f(i, j):
            if memo[i][j] >= 0:
                return memo[i][j]
            if i == 0 and j == 0:
                return 1
            elif i <= 0 or j <= 0:
                return 0
            else:
                memo[i][j] = (f(i-1,j-1) + (i-1)*f(i-1,j) % mod) % mod
                return memo[i][j]
        return f(n,k)

class Solution:
    def rearrangeSticks(self, n: int, k: int) -> int:
        if not n and not k: return 1
        if not n or not k: return 0
        dp = [[0] * (k + 1) for _ in range(n + 1)]
        # dp[n][k]
        # f(i,j) = f(i-1,j-1) + (i-1)*f(i-1,j)
        mod = 10**9+7
        dp[0][0] = 1
        for i in range(1, n + 1):
            for j in range(1, k + 1):
                dp[i][j] += dp[i - 1][j - 1] + (i - 1) * dp[i - 1][j] % mod
                dp[i][j] %= mod
        return dp[n][k]

Search

    Table of Contents