AT_agc002_f [AGC002F] Leftmost Ball 思考--zhengjun

发布时间 2023-07-22 12:17:45作者: A_zjzj

思维 + 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;
}