600pt. NoRepeatPlaylist
dp[i][j] 表示构造到第i首歌时,用了j首不同的歌的排列组合数。
状态转移方程为
dp[i][j]=dp[i-1][j-1]*(N-(j-1))+dp[i-1][j]*(j-M);
注:我们构造到第i首歌时,用了j种不同的歌,那么在第i个位置。我们可以有两种选择。
(1)选择新歌,前面i-1个位置用了j-1首不同的歌,那么对于每个dp[i-1][j-1],在第i个位置我们还有
(N-(j-1))首不同的歌可以选择。
(2)选择旧歌,前面i-1个位置用了j首不同的歌,那么紧靠第i个位置的前M个位置(i-M) 到
(i-1) 必须是不同的M首歌,j首之中占了M首歌,那么对于每个dp[i-1][j],在第i个位置,我们还有 (j-M)
首不同的歌可以选择。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
const int MOD = 1000000007;
long long dp[105][105];
//dp[i][j] 表示构造到第i首歌时,用了j首不同的歌的排列组合数
//状态转移方程为 dp[i][j]=dp[i-1][j-1]*(N-(j-1))+dp[i-1][j]*(j-M);
class NoRepeatPlaylist
{
public:
int numPlaylists(int N, int M, int P)
{
memset(dp,0,sizeof(dp));
dp[1][1]=N;
for(int i=2;i<=P;i++)
{
for(int j=1;j<=N && j<=i;j++)
{
dp[i][j]=dp[i-1][j-1]*(N-(j-1))%MOD;
if(j-M>0)
dp[i][j]+=dp[i-1][j]*(j-M)%MOD;
}
}
return dp[P][N]%MOD;
}
};