TopCoder SRM 531 Div1 Easy NoRepeatPlaylist
問題
N曲の曲からP曲を重複を許して、以下の条件を満たすよう選ぶ。
選び方は何通りあるか、mod 10^9 + 7で求めよ。
条件:
全ての曲が少なくとも一度以上選ばれる。
同じ曲は間に少なくともM曲のほかの曲を挟む。
制約条件
N,M,P≦100
方針
dp[i]を、i曲ちょうどを使って、同じ曲の間には少なくともM曲他の曲が挟まっているような曲の選び方の場合の数とする。
dp[M+1]は(M+1)!通りの選び方がある。
i曲「以下」で条件を満たすのは、N*(N-1)*…*(N-M)*(N-M)*…*(N-M)通り。
ここからj曲(j<i)で条件を満たすものを引けば、i曲ちょうどで条件を満たす曲の選び方の場合の数がわかる。
包除原理を使っても解けるらしい。
ソースコード
const int mod=1000000007; ll dp[101], C[101][101]; class NoRepeatPlaylist { public: int numPlaylists(int N, int M, int P) { if(M+1>P){ ll res=1; rep(i,N)(res*=i+1)%=mod; return res; } memset(dp,0,sizeof(dp)); rep(i,101)rep(j,i+1)C[i][j]=i==0||i==j?1:(C[i-1][j-1]+C[i-1][j])%mod; dp[M+1]=1; rep(i,M+1)(dp[M+1]*=i+1)%=mod; for(int i=M+2;i<=N;i++){ ll tmp=1; rep(j,P)(tmp*=max(i-j,i-M))%=mod; rep(j,i)(dp[i]+=dp[j]*C[i][j]%mod)%=mod; dp[i]=(mod-dp[i]+tmp)%mod; } return dp[N]; } };