思维 + dp。
如果像题意那样先放球再染色的话不是很好做。
所以考虑有 \(n\) 个白球,\(n\) 种其他颜色的球各 \(k-1\) 个。
那么限制就是说对于每个前缀,白球的个数 \(\ge\) 其他颜色球的种数。
所以就可以设 \(f_{i,j}\) 为放了 \(i\) 个白球,\(j\) 种颜色的 \(k-1\) 个球的方案数。
那么剩下的 \(nk-i-j\times(k-1)\) 个空位中:
-
要么第一个放白球,转移到 \(f_{i+1,j}\),方案数为 \(1\)。
-
要么第一个放其他颜色的球,转移到 \(f_{i,j+1}\),方案数为 \((n-j)\times \binom{nk-i-j\times(k-1)-1}{k-2}\),意思是选出一种颜色填,并且剩下的空中第一个强制选择该颜色的球。
所以特判掉 \(k=1\) 的输出 \(1\) 即可。
代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2e3+10,M=N*N,mod=1e9+7;
int n,k;
int fac[M],ifac[M];
ll qpow(ll x,ll y=mod-2){
ll ans=1;
for(;y;(x*=x)%=mod,y>>=1)if(y&1)(ans*=x)%=mod;
return ans;
}
void init(int n){
for(int i=fac[0]=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
ifac[n]=qpow(fac[n]);
for(int i=n;i>=1;i--)ifac[i-1]=1ll*ifac[i]*i%mod;
}
int C(int n,int m){
if(0>m||m>n)return 0;
return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int f[N][N];
int main(){
freopen(".in","r",stdin);
//freopen(".out","w",stdout);
cin>>n>>k,init(n*k);
if(k==1)return puts("1"),0;
for(int i=1;i<=n;i++){
f[i][0]=1;
for(int j=1;j<=i;j++){
f[i][j]=(f[i-1][j]+1ll*f[i][j-1]*C(n*k-i-(j-1)*(k-1)-1,k-2)%mod*(n-j+1))%mod;
}
}
cout<<f[n][n];
return 0;
}
标签:agc002,Ball,return,ifac,--,ll,int,ans,mod
From: https://www.cnblogs.com/A-zjzj/p/17573145.html