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;
}
};