小 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;
}
原文:https://www.cnblogs.com/LSlzf/p/12204093.html