LintCode1574: Music Playlist (DP好题)

  1. Music Playlist

Ming likes to listen to music on his mobile phone while traveling by train. He has a n song on his mobile phone. He can listen to the p song on the whole train, so he wants to generate a playlist to produce a p song. The rules for this playlist are:
(1) Each song must be played at least once
(2) In the middle of two songs, there are at least m other songs.
Xiao Ming wants to know how many different playlists can be produced. Since the result is large, the output result is the remainder of the 1000000007.

Example
Example 1:

Input:2,0,3
Output:6
Explanation:
There are 2 songs in total, which are recorded as A and B.
No other songs are needed between the two songs.
There are 6 programs in AAB, ABA, BAA, BBA, BAB and ABB.
Example 2:

Input:1,1,3
Output:0
Explanation:There is only one AAA scheme, but there are at least one other song in the middle of the same song, so there is no scheme that meets the requirements.
Notice
1 \leq n \leq 1001≤n≤100
1 \leq m \leq n1≤m≤n
1 \leq p \leq 1001≤p≤100

解法1:DP
dp[i][j]为前i首歌里面有j个unique的歌。
可知dp[i][j]可由dp[i - 1][j - 1]dp[i - 1][j]转换而来。
dp[i-1][j-1]表示前i-1首歌里面有j-1首unique的歌,那么还有1首unique的歌就从n-(j-1)首unique的歌库里面选就好了。
dp[i-1][j]表示前i-1首歌里面有j首unique的歌,那么第i首歌就从这第j首里面选。注意连续的m首歌里面不能有重复的,所以第j首歌只能从前面的j-m首歌里面选。

为什么dp[i][j]不能由dp[i][j - 1]转换而来呢?因为前i首歌已经用完了,只有j-1首unique的歌,那没有办法再加一首unique的歌了,因为i首歌已经用完了。
为什么dp[i][j]不能由dp[i ][j - 2 ]转换而来呢?原因跟dp[i][j]不能由dp[i][j-1]转换而来相同。
为什么dp[i][j]不能由dp[i - 2][j ]转换而来呢?因为这样很多歌曲就跟dp[i-1][j]搞重复了。
为什么dp[i][j]不能由dp[i - 1][j-2 ]转换而来呢?因为2首unique歌不能插到一首歌的位置。

注意:
1)dp[0][0]应该为1,dp[1][1]不一定为1,因为dp[1][1]表示前1首歌里面有1首unique的歌,那么实际上有n种选择。如果dp[0][0]设为0,那么dp[1][1]也是0了。
2)相乘和相加的结果都要mod 1000000007

class Solution {
public:
    /**
     * @param n: the number of on his mobile phone
     * @param m: in the middle of two songs, there are at least m other songs
     * @param p: the number of songs he can listen to
     * @return: the number of playlists
     */
    int getAns(int n, int m, int p) {
        vector<vector<long long>> dp(p + 1, vector<long long>(n + 1));
        dp[0][0] = 1;
        
        for (int i = 1; i <= p; ++i) {
            for (int j = 1; j <= n; ++j) {
                //dp[i][j] can be transformed from dp[i - 1][j - 1] and dp[i - 1][j]
                //dp[i - 1][j - 1]: in the first i - 1 songs, there are j - 1 unique songs 
                dp[i][j] = dp[i - 1][j - 1] * (n - j + 1) % 1000000007;
                //dp[i - 1][j]: in the first i - 1 songs, there are already j unique songs
                if (j > m) {
                    dp[i][j] = (dp[i][j] + (dp[i - 1][j] * (j - m) % 1000000007)) % 1000000007;
                }
            }
        }   
        return (int)dp[p][n];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值