#排列组合,dp#AT2000 [AGC002F] Leftmost Ball

洛谷题目传送门

ATCODER传送门


分析

\(dp[i][j]\)表示放完\(i\)个白球和\(j\)种有颜色的球的情况

首先\(dp[i][j]\)显然可以从\(dp[i-1][j]\)转移,

然后也可以从\(dp[i][j-1]\)转移,选择剩下\(n-j+1\)种颜色填入,

那么现在要在剩下的\(n\times k-i-1-(j-1)\times(k-1)\)个位置中

选择\(k-2\)个位置填入下一种颜色,

也就是\(C(n\times k-i-1-(j-1)\times (k-1),k-2)\)

  1. 排列长度\(n\times k\),放入\(i\)个白球和\(j-1\)种颜色(每种颜色为\(k-1\)个)
  2. 为什么是\(k-2\),如果不指定当前剩下的第一个位置为该颜色,那么当选择其它颜色填入时就会算重,并且剩下的总位置也要减1

预处理阶乘和乘法逆元就可以了
The End。


代码

#include <cstdio>
#define rr register
using namespace std;
const int mod=1000000007,N=2001;
int n,k,inv[N*N],fac[N*N],dp[N][N];
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed c(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;}
signed main(){
	inv[0]=inv[1]=fac[0]=fac[1]=1,scanf("%d%d",&n,&k);
	if (k==1) return !putchar(49);
	for (rr int i=2;i<=n*k;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
	for (rr int i=2;i<=n*k;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
	for (rr int i=0;i<=n;++i) dp[i][0]=1;
	for (rr int i=1;i<=n;++i) for (rr int j=1;j<=i;++j)
	    dp[i][j]=mo(dp[i-1][j],1ll*dp[i][j-1]*(n-j+1)%mod*c(n*k-i-1-(j-1)*(k-1),k-2)%mod);
	return !printf("%d\n",dp[n][n]);
}
posted @ 2020-08-10 11:54  lemondinosaur  阅读(87)  评论(0编辑  收藏  举报