题解
首先可以发现(n)这个楼将序列分成的两半
前一半就是让你选出(A)个数,并且以(n)为结尾,每个数到下一个数的这段区间的数一定小于这个数
那么这可以看做是什么呢?
是不是可以把每段区间内的数看做是一个环然后做环排列?
最大的数就当做环首
这就是((A-1))个环排列
那么这就是第一类斯特林数了
(S(n,m)=(n-1)S(n-1,m)+S(n-1,m-1))表示对于新加入的数是放入以前的环中还是新开一个环
那么就枚举楼(n)在哪里,然后前后做环排列即可
这样单次询问复杂度是(O(n))
可以发现把(n)拎出来之后就剩下了(A+B-2)个环排列,把((n-1))个数排成(A+B-2)个环排列然后把任意(A-1)个弄到(n)的前面就是答案了
代码
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 50050 ;
const int mod = 1e9 + 7 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , A , B , ans ;
int fac[M] , inv[M] , finv[M] , s[M][205] ;
inline int C(int n , int m) {
return 1LL * fac[n] * finv[m] % mod * finv[n - m] % mod ;
}
int main() {
fac[0] = 1 ;
for(int i = 1 ; i <= 50000 ; i ++) fac[i] = 1LL * fac[i - 1] * i % mod ;
inv[1] = 1 ;
for(int i = 2 ; i <= 50000 ; i ++) inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod ;
finv[0] = 1 ;
for(int i = 1 ; i <= 50000 ; i ++) finv[i] = 1LL * finv[i - 1] * inv[i] % mod ;
s[0][0] = 1 ;
for(int i = 1 ; i <= 50000 ; i ++)
for(int j = 1 ; j <= min(200 , i) ; j ++)
s[i][j] = (s[i - 1][j - 1] + 1LL * (i - 1) * s[i - 1][j] % mod) % mod ;
int Case = read() ;
while(Case --) {
n = read() ; A = read() ; B = read() ; ans = 0 ;
printf("%d
",1LL * s[n - 1][A + B - 2] * C(A + B - 2 , A - 1) % mod) ;
}
return 0 ;
}