问题相当于计算有n个颜色0的球,其他n-1种颜色各有m-1个球,一个合法的序列是任意一个前缀中颜色0的球的数量>其他颜色的颜色数量
为了方便计数,我们不妨把每个颜色为0的球和一个颜色捆绑,即对于序列中(除了颜色0)出现的第i种颜色,我们将它捆绑到第i个颜色为0的球身上
然后可以设出一个dp,f[i][j][k]代表放了i个球,已经放了j个颜色为0的球,其他颜色已经出现了k种的方案数
状态数
O(n3k)
O
(
n
3
k
)
,转移
O(1)
O
(
1
)
然后可以发现第一维i是没有必要的qaq
可以直接dp,f[i][j]表示放了i个颜色为0的球,其他颜色已经出现了k种的方案数
两种转移,放一个颜色为0的球和放一种颜色的所有球,组合数什么的算一下
状态数
O(n2)
O
(
n
2
)
,转移
O(1)
O
(
1
)
最后答案乘上 n! n ! 代表给颜色0的不同捆绑方案
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;
const int maxn = 2000*2000+5;
const int mod = 1e9+7;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}
int pw(int x,int k)
{
int re=1;
for(;k;k>>=1,x=(ll)x*x%mod) if(k&1)
re=(ll)re*x%mod;
return re;
}
int inv(int x){ return pw(x,mod-2); }
int s[maxn],invs[maxn];
void pre()
{
s[0]=1; for(int i=1;i<maxn;i++) s[i]=(ll)s[i-1]*i%mod;
invs[maxn-1]=inv(s[maxn-1]);
for(int i=maxn-2;i>=0;i--) invs[i]=(ll)invs[i+1]*(i+1)%mod;
}
int C(int n,int m){return (ll)s[n]*invs[m]%mod*invs[n-m]%mod;}
int n,m;
int f[2005];
int main()
{
pre();
scanf("%d%d",&n,&m); int u=n*m;
if(m==1) return puts("1"),0;
f[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<i;j++)
add(f[j+1],(ll)f[j]*C(u-i-j*(m-1)-1,m-2)%mod);
}
int ans=f[n];
ans=(ll)ans*s[n]%mod;
printf("%d\n",ans);
return 0;
}