1. 程式人生 > 實用技巧 >[HDU4372] Count the Buildings

[HDU4372] Count the Buildings

前言

第一類斯特林數,有思維難度

題目

HDU

講解

考慮最高的那棟房子會被兩邊計算,除去它,還剩\(n-1\)棟房子

左邊能看見的有\(F-1\)棟房子,右邊能看見\(B-1\)棟房子

我們先考慮左邊一邊

如果我們選出了能被看見的\(F-1\)棟房子,剩下的所有高度小於它們的房子都會在它們的右邊

對於每一棟選出的房子都會形成一條長龍,後面跟的就是高度小於它的房子,但不一定高度小於它的房子剛好跟在它後面

把這個看作一組,發現這一組便是第一類斯特林數中的一個環(重難點)

我們總共需要\(F-1+B-1\)個這樣的環,方案數即為\(s[n-1][F+B-2]\),這裡的\(s\)陣列是第一類斯特林數

然後我們要在\(F+B-2\)個環中選出\(F-1\)個放在左邊,順序為根據排頭高度遞增

所以答案還要乘上\(C_{F+B-2}^{F-1}\)

最終的答案即為\(s[n-1][F+B-2]*C_{F+B-2}^{F-1}\)

記得判無解

程式碼

int C[MAXN][MAXN],s[MAXN][MAXN];
void pre(int x)
{
	s[0][0] = C[0][0] = 1;
	for(int i = 1;i <= x;++ i)
	{
		C[i][0] = 1;
		for(int j = 1;j <= i;++ j)
			C[i][j] = (C[i-1][j-1] + C[i-1][j]) % MOD,s[i][j] = (s[i-1][j-1] + 1ll * (i-1) * s[i-1][j]) % MOD;
	}
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	pre(2000);
	for(int T = Read(); T ;-- T)
	{
		n = Read();F = Read();B = Read();
		if(F+B-2 > n-1) {Put(0,'\n');continue;}
		Put(1ll * s[n-1][F+B-2] * C[F+B-2][F-1] % MOD,'\n');
	}
	return 0;
}