问题描述
小 Z 是一个很有名的建筑师,有一天他接到了一个很奇怪的任务:在数轴上建 n 个建筑,每个建筑的高度是 1 到 n 之间的一个整数。
小 Z 有很严重的强迫症,他不喜欢有两个建筑的高度相同。另外小 Z 觉得如果从最左边(所有建筑都在右边)看能看到 A 个建筑,从最右边(所有建筑都在左边)看能看到 B 个建筑,这样的建筑群有着独特的美感。现在,小 Z 想知道满足上述所有条件的建筑方案有多少种?
如果建筑 i 的左(右)边没有任何建造比它高,则建筑 i 可以从左(右)边看到。两种方案不同,当且仅当存在某个建筑在两种方案下的高度不同。
输入格式
第一行一个整数 T,代表 T 组数据。 接下来 T 行,每行三个整数 n,A,B。
输出格式
对于每组数据输出一行答案 ( ext{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)组放在最高建筑的左边,其余的放在右边。由于要满足要求,这左边相当于自动排序了,不需要计算排列数。所以,最后的答案就是:
代码
#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
",S[n-1][a+b-2]*C[a+b-2][a-1]%mod);
}
return 0;
}