# 920. Number of Music Playlists

**<font color=red>难度: Hard</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/number-of-music-playlists/description/

> 内容描述

```
Your music player contains N different songs and she wants to listen to L (not necessarily different) songs during your trip.  You create a playlist so that:

Every song is played at least once
A song can only be played again only if K other songs have been played
Return the number of possible playlists.  As the answer can be very large, return it modulo 10^9 + 7.

 

Example 1:

Input: N = 3, L = 3, K = 1
Output: 6
Explanation: There are 6 possible playlists. [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1].
Example 2:

Input: N = 2, L = 3, K = 0
Output: 6
Explanation: There are 6 possible playlists. [1, 1, 2], [1, 2, 1], [2, 1, 1], [2, 2, 1], [2, 1, 2], [1, 2, 2]
Example 3:

Input: N = 2, L = 3, K = 1
Output: 2
Explanation: There are 2 possible playlists. [1, 2, 1], [2, 1, 2]
 

Note:

0 <= K < N <= L <= 100
```

## 解题方案

> 思路 1
******- 时间复杂度: O(N*L)******- 空间复杂度: O(N*L)******



DP

- dp[i][j]代表用j首不同的歌曲来组成播放列表的前i首歌的可能性，初始化dp[0][0] = 1,其他元素全为0,确定返回dp[L][N]
- 第一种可能性，第i首歌与前i-1首歌均不重复，先用j-1首不同的歌组成播放列表的前i-1首歌，然后挑选一首与那j-1首歌都不同的歌来作为播放列表的第i首歌
   - 这种情况毫无疑问不需要担心第i首歌与它前面的K首歌出现重复 
   - 状态转移方程为dp[i][j] += dp[i-1][j-1] * (N-j+1) % M
- 第二种可能性，第i首歌与前i-1首歌有重复，先用j首不同的歌组成播放列表的前i-1首歌，然后挑选一首与那j-1首歌重复的歌来作为播放列表的第i首歌
    - 我们需要保证第i首歌与它的前K首歌不出现重复
    - 如果所有不重复的歌都不大于K（即j <= K)，那第i首歌与它前面的K首歌必然出现重复，因此没有这种排列
    - 如果j>K，状态转移方程为dp[i][j] += dp[i-1][j] * (j-K) % M, 
    我们需要保证第i首歌与它前面的K首歌都不相同，所以第i首歌只能从j-K首歌里面选取
    
- 最后返回dp[L][N]，即用N首不同的歌来组成播放列表的前L首歌



```python
class Solution(object):
    def numMusicPlaylists(self, N, L, K):
        """
        :type N: int
        :type L: int
        :type K: int
        :rtype: int
        """
        M = 10**9+7
        dp = [[0] * (N+1) for i in range(L+1)] # dp[i][j]代表用j首不同的歌曲来组成播放列表的前i首歌的可能性
        dp[0][0] = 1 # 初始化为1种
        for i in range(1, L+1):
            for j in range(1, N+1):
                dp[i][j] += dp[i-1][j-1] * (N-j+1) % M # 第一种可能性
                if j > K:             
                    dp[i][j] += dp[i-1][j] * (j-K) % M # 第二种可能性
        return dp[L][N] % M
```
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
