#排列组合,dp#AT2000 [AGC002F] Leftmost Ball
分析
设\(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)\)
- 排列长度\(n\times k\),放入\(i\)个白球和\(j-1\)种颜色(每种颜色为\(k-1\)个)
- 为什么是\(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]);
}