版权声明:本文为博主原创文章,请随意转载(注明出处)。 https://blog.csdn.net/can919/article/details/82733596
题意
Snuke喜欢五颜六色的球。他总共有N×K个球,有N种颜色,每种颜色的球有K个。颜色编号为1到N。他将按照任意顺序排列所有球。然后,对于每种颜色,他将该颜色的最左边的球涂成颜色0,颜色0不同于N种原始颜色中的任何颜色。如将球排列为(1,2,1,2),染色后就变为 (0,0,1,2)。
所有操作后,球的颜色序列有多少种,求这个方案数mod 10^9+7。
题解
发现一个性质:对任何前缀,0的个数必须
出现的其它颜色种类数
可定义
表示有i个0,j种颜色都已经放完的方案数
转移:
新放了一个0
新放了一种颜色,这个颜色的第一个球必须放在最开始(表示这时候已经出现过这种颜色),(还有一个球变为了0)这种颜色还剩下
个球可以随便放,则需乘上组合数
最后答案为
(dp时没有考虑颜色的区别,还需乘上颜色的排列数)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=2005,MOD=1000000007;
int PowMod(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)
ret=1LL*ret*a%MOD;
a=1LL*a*a%MOD;
b>>=1;
}
return ret;
}
int fac[MAXN*MAXN],ifac[MAXN*MAXN];
void Init()
{
fac[0]=1;
for(int i=1;i<MAXN*MAXN;i++)
fac[i]=1LL*fac[i-1]*i%MOD;
ifac[MAXN*MAXN-1]=PowMod(fac[MAXN*MAXN-1],MOD-2);
for(int i=MAXN*MAXN-2;i>=0;i--)
ifac[i]=1LL*ifac[i+1]*(i+1)%MOD;
}
int C(int n,int r)
{return 1LL*fac[n]*ifac[n-r]%MOD*ifac[r]%MOD;}
int N,K,dp[MAXN][MAXN];
int main()
{
Init();
scanf("%d%d",&N,&K);
if(K==1)
{
puts("1");
return 0;
}
dp[0][0]=1;
for(int i=0;i<=N;i++)
for(int j=0;j<=i;j++)
{
if(i)
dp[i][j]=(dp[i][j]+dp[i-1][j])%MOD;
if(j)
dp[i][j]=(dp[i][j]+1LL*dp[i][j-1]*C(N*K-i-(K-1)*(j-1)-1,K-2)%MOD)%MOD;
}
int ans=1LL*dp[N][N]*fac[N]%MOD;
printf("%d\n",ans);
return 0;
}