题解 AT2000 【[AGC002F] Leftmost Ball】

\[\huge\mathbb{DESCRIPTION} \]

编号:\(AT2000\)
算法:乘法逆元、\(\mathcal{DP}\)
时间复杂度:\(\mathcal O(N^2)\)

\[\huge\mathbb{SOL} \]

我们直接来推式子吧...
首先如果\(K=1\),就直接输出1。
\(Dp[i][j]\)表示用了\(i\)个白球和\(j\)个彩色球的合法的方案数量。
首先,如果你已经放了\(i-1\)个白球和\(j\)个彩球,这时你再在后面放一个白球肯定不影响。
因此,\(Dp[i][j]\)可以由\(Dp[i-1][j]\)转移过来。
其次,\(Dp[i][j]\)也可以由\(Dp[i][j-1]\)转移而来。
我们看看为什么吧...
因为已经选了\(j-1\)个彩球,所以还有\(N-j+1\)个彩球没有选。
如果我们选了某一种颜色的球,我们就必须从这种颜色的\(K\)个彩球里选一个放上。
此时,这种颜色的彩球减少了\(2\)个,一个被涂成了白色,一个没有变色。
所以还剩\(K-2\)个这种彩球。
所以我们需要在剩下的\(N*K-i-1(j-1)*(K-1)\)个位子中选\(K-2\)个位子。
所以我们就得出了状态转移方程:

\[Dp[i][j]=Dp[i-1][j]+Dp[i][j-1]*(N-j+1)*C_{N*K-i-1(j-1)*(K-1)}^{K-2} \]

转移前求一下阶乘和逆元即可。

\[\huge\mathbb{CODE} \]

#include<bits/stdc++.h>
#define MOD 1000000007
#define MAX 2001
using namespace std;
long long N,K;
long long Inv[MAX*MAX];
long long Dp[MAX][MAX];
long long Factorial[MAX*MAX];
inline long long Quick_Power(long long X,int P)
{
	register long long Return;
	Return=1;
	while(P)
	{
		if(P&1)
		{
			Return=Return*X%MOD;
		}
		X=X*X%MOD;
		P>>=1;
	}
	return Return;
}
inline long long Combination(long long A,long long B)
{
	return Factorial[A]*Inv[B]%MOD*Inv[A-B]%MOD; 
}
int main(void)
{
	register long long i,j;
	cin>>N>>K;
	if(K==1)
	{
		cout<<1<<endl;
		return 0;
	}
	Factorial[0]=1;
	for(i=1;i<=N*K;i++)
	{
		Factorial[i]=Factorial[i-1]*i%MOD;
	}
	Inv[N*K]=Quick_Power(Factorial[N*K],MOD-2);
	for(i=N*K-1;i>=0;i--)
	{
		Inv[i]=Inv[i+1]*(i+1)%MOD;
	}
	Dp[0][0]=1;
	for(i=1;i<=N;i++)
	{
		for(j=0;j<=i;j++)
		{
			if(!j)
			{
				Dp[i][j]=Dp[i-1][j];
				continue;
			}
			Dp[i][j]=Dp[i-1][j]+Dp[i][j-1]*(N-j+1)%MOD*Combination(N*K-i-1-(j-1)*(K-1),K-2)%MOD;
		}
	}
	cout<<Dp[N][N]<<endl;
	return 0;
}
posted @ 2020-08-13 13:30  Bushuai_Tang  阅读(202)  评论(1编辑  收藏  举报