显然,对于任意方案,始终存在一个最高的建筑在中间,我们以此来划分左右进行讨论。
对于左边的 个建筑,我们先讨论这 个建筑的某一个建筑。
由于这个建筑能够被看到,那么就说明这个建筑可能挡住了若干个建筑,我们把这若干个建筑的数目记为 ,由于我们始终是看不到这 个建筑的,所以这 个建筑的排列对我们的答案无影响,而 个建筑的排列数目为 。
接下来我们转换一下。
的建筑的排列等价于给定 个数,其中确定一个数放于队首,其他数随意排列的方案数,亦即 个数的圆排列数目。
所以左边应该就有 个圆排列,同理右边应该有 个圆排列。
所以我们同时考虑,就变成了在 个数划分成 个圆排列的方案数。
即第一类斯特林数:
但是由于我们还要将这 中的 个数放在最高建筑的左边,所以我们还要算上一个组合数:
于是我们得到最后的答案:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll M=2e2+5;
const ll N=5e4+5;
const ll Mod=1e9+7;
ll t,n,a,b,C[M][M],S[N][M];
inline ll add(ll x,ll y) {
return x+y>=Mod?x+y-Mod:x+y;
}
inline ll mul(ll x,ll y) {
return x*y%Mod;
}
int main() {
for(ll i=0;i<M;i++) C[i][0]=1;
for(ll i=1;i<M;i++) for(ll j=1;j<=i;j++)
C[i][j]=add(C[i-1][j],C[i-1][j-1]);
for(ll i=0;i<M;i++) S[i][i]=1;
for(ll i=2;i<N;i++) for(ll j=1;j<min(i,M);j++) S[i][j]=add(mul(i-1,S[i-1][j]),S[i-1][j-1]);
scanf("%lld",&t);
while(t--) {
scanf("%lld%lld%lld",&n,&a,&b);
if(a+b>n+1){
puts("0");continue;
}
printf("%lld\n",mul(C[a+b-2][a-1],S[n-1][a+b-2]));
}
return 0;
}