[洛谷P4609] FJOI2016 建筑师

问题描述

小 Z 是一个很有名的建筑师,有一天他接到了一个很奇怪的任务:在数轴上建 n 个建筑,每个建筑的高度是 1 到 n 之间的一个整数。

小 Z 有很严重的强迫症,他不喜欢有两个建筑的高度相同。另外小 Z 觉得如果从最左边(所有建筑都在右边)看能看到 A 个建筑,从最右边(所有建筑都在左边)看能看到 B 个建筑,这样的建筑群有着独特的美感。现在,小 Z 想知道满足上述所有条件的建筑方案有多少种?

如果建筑 i 的左(右)边没有任何建造比它高,则建筑 i 可以从左(右)边看到。两种方案不同,当且仅当存在某个建筑在两种方案下的高度不同。

输入格式

第一行一个整数 T,代表 T 组数据。 接下来 T 行,每行三个整数 n,A,B。

输出格式

对于每组数据输出一行答案 \(\text{mod } 10^9+7\)

样例输入

2
3 2 2
3 1 2

样例输出

2
1

数据范围

对于 \(10 \%\) 的数据 : \(1 \leq n \leq 10\)

对于 \(20 \%\) 的数据 : \(1 \leq n \leq 100\)

对于 \(40 \%\) 的数据 : \(1 \leq n \leq 50000, \ 1 \leq T \leq 5\)

对于 \(100 \%\) 的数据 :\(1 \leq n \leq 50000, \ 1 \leq A, B \leq 100, \ 1 \leq T \leq 200000\)

解析

通过题目的描述,我们可以发现,它的意思大概就是这个样子:

对于每一个可以看到的建筑物,他的后面都会有比自己要矮的建筑(或者没有)。按照这个方法来分块,假设某个块的大小为 \(x\) ,由于块中最高的一定在最外面(不然会看到其他的),这个块的排列方案数就是\((x-1)!\)。由组合意义,相当于不算最高的,在\(n-1\)个数中划分成\(A+B-2\)组,每组进行圆排列。这和第一类斯特林数的形式是一样的。然后,我们要在\(A+B-2\)组中选择\(A-1\)组放在最高建筑的左边,其余的放在右边。由于要满足要求,这左边相当于自动排序了,不需要计算排列数。所以,最后的答案就是:

\[\begin{bmatrix}n-1 \\ A+B-2\end{bmatrix} \times \binom{A+B-2}{A-1} \]

代码

#include <iostream>
#include <cstdio>
#define int long long
#define N 50002
#define M 202
using namespace std;
const int mod=1000000007;
int t,n,a,b,i,j,S[N][M],C[M][M];
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
signed main()
{
	t=read();
	S[0][0]=1;
	for(i=1;i<=50000;i++){
		for(j=1;j<=200;j++) S[i][j]=(S[i-1][j-1]+(i-1)*S[i-1][j]%mod)%mod;
	}
	C[0][0]=1;
	for(i=1;i<=200;i++){
		C[i][0]=1;
		for(j=1;j<=200;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
	}
	while(t--){
		n=read();a=read();b=read();
		printf("%lld\n",S[n-1][a+b-2]*C[a+b-2][a-1]%mod);
	}
	return 0;
}
posted @ 2020-01-17 08:30  CJlzf  阅读(96)  评论(0编辑  收藏  举报