P4609 [FJOI2016] 建筑师 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题解:
最大的那一个数肯定会左右都能看见n的左边能看见a-1个,右边能看见b-1个
把每个能看见的建筑与其后面的数看成一个组合,每个组是一个圆,因为每个组(这个组的建筑个数为)的排列数为(n-1)!. 问题转化为n-1个数划分为a+b-2个圆排列,因为对于左边a-1个圆,自动为从小到大排序,因此不用考虑左边这些组的排列,只有一个排列. 因此答案为stir[n-1][a+b-2]*C[a+b-2][a-1]
AC代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int mod=1e9 + 7, N = 5e4+10, M = 210;
int main(){
vector<vector<int> > C(M,vector<int>(M)), stir(N,vector<int>(M));
stir[0][0] = 1,C[0][0] = 1;
for(int i=1;i<N;i++){
for(int j=1;j<=i&&j<M;j++)stir[i][j] = (1ll*stir[i-1][j-1] + (i-1ll) * stir[i-1][j]%mod)%mod;
}
for(int i=1;i < M; i++){
C[i][0] = 1;
for(int j = 1; j <= i; j++) C[i][j] = (1ll * C[i - 1][j] + C[i - 1][j - 1])%mod;
}
int T;
cin >> T;
while(T--){
int n, A, B;
cin >> n >> A >> B;
cout << 1ll * stir[n - 1][A + B - 2] * C[A + B - 2][A - 1] % mod << endl;
}
}