ATcoder 2000 Leftmost Ball
Problem Statement
Snuke loves colorful balls. He has a total of N×K balls, K in each of his favorite N colors. The colors are numbered 1 through N.
He will arrange all of the balls in a row from left to right, in arbitrary order. Then, for each of the N colors, he will paint the leftmost ball of that color into color 0, a color different from any of the N original colors.
After painting, how many sequences of the colors of the balls are possible? Find this number modulo 109+7.
Constraints
- 1≤N,K≤2,000
Input
The input is given from Standard Input in the following format:
N K
Output
Print the number of the possible sequences of the colors of the balls after painting, modulo 109+7.
Sample Input 1
2 2
Sample Output 1
4
The following 4 sequences are possible:
- (0,1,0,2)
- (0,0,1,2)
- (0,2,0,1)
- (0,0,2,1)
Sample Input 2
3 1
Sample Output 2
1
The following 1 sequence is possible:
- (0,0,0)
Sample Input 3
2 3
Sample Output 3
14
Sample Input 4
2000 2000
Sample Output 4
546381702
不妨把0颜色看成白球,把其他颜色看成彩球,那么我们来讨论一下什么样的序列是合法的。
仅有一个序列中的每一个白球都能在其后方匹配到一个是其颜色里出现第一次的彩球,这个序列才合法。
所以我们就可以从后向前dp,状态的定义和转移在代码里都有,只不过特判一下k==1直接输出1就好了。
/* f[i][j] 表示 已经出现过 i种颜色的球, 并且还剩j种颜色的球没有被匹配的方案数。 考虑加入一种新球的话: f[i+1][j+1] += f[i][j] * (n-i) * C(k*(i+1)-j-2,k-2) 考虑加入一种白球的话: f[i][j-1] += f[i][j] 初始化 f[0][0] = 1 */ #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=2005; const int ha=1000000007; int jc[maxn*maxn],ni[maxn*maxn]; int n,k,f[maxn][maxn]; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } inline void init(){ jc[0]=1; for(int i=1;i<=4004000;i++) jc[i]=jc[i-1]*(ll)i%ha; ni[4004000]=ksm(jc[4004000],ha-2); for(int i=4004000;i;i--) ni[i-1]=ni[i]*(ll)i%ha; } inline int getC(int x,int y){ return jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha; } inline void dp(){ f[0][0]=1; for(int i=0;i<=n;i++) for(int j=i;j>=0;j--) if(f[i][j]){ f[i+1][j+1]=add(f[i+1][j+1],f[i][j]*(ll)(n-i)%ha*(ll)getC(k*(i+1)-j-2,k-2)%ha); if(j) f[i][j-1]=add(f[i][j-1],f[i][j]); } /* for(int i=0;i<=n;i++){ for(int j=0;j<=i;j++) printf("%d ",f[i][j]); puts(""); } */ } int main(){ init(); scanf("%d%d",&n,&k); if(k==1) puts("1"); else{ dp(); printf("%d\n",f[n][0]); } return 0; }
我爱学习,学习使我快乐