题目
问有多少个 1 ∼ n 1\sim n 1∼n的排列,满足从左边只走上坡能看到 a a a个数,从右边只走上坡能看到 b b b个数
分析
那么先把最高值分开,那么左边有
a
−
1
a-1
a−1个,右边有
b
−
1
b-1
b−1个,那么共有
a
+
b
−
2
a+b-2
a+b−2个,而样子类似合唱队形还可以旋转,所以其实就是在
n
−
1
n-1
n−1个数中坐在
a
+
b
−
2
a+b-2
a+b−2个圆桌的方案数,再选择
a
+
b
−
2
a+b-2
a+b−2个数中选择
a
−
1
a-1
a−1个放左边,那么总而言之,答案就是
C
(
a
+
b
−
2
,
a
−
1
)
∗
S
t
i
r
l
i
n
g
(
n
−
1
,
a
+
b
−
2
)
C(a+b-2,a-1)*Stirling(n-1,a+b-2)
C(a+b−2,a−1)∗Stirling(n−1,a+b−2),后面是第一类斯特林数,时间复杂度
O
(
n
a
+
T
)
O(na+T)
O(na+T)
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=50001,M=201,mod=1e9+7;
int stir[N][M],c[M][M];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
signed main(){
stir[0][0]=c[0][0]=1;
for (rr int i=1;i<N;++i)
for (rr int j=1;j<=i&&j<M;++j)
stir[i][j]=mo(stir[i-1][j-1],1ll*(i-1)*stir[i-1][j]%mod);
for (rr int i=1;i<M;++i){
c[i][0]=1;
for (rr int j=1;j<=i;++j)
c[i][j]=mo(c[i-1][j],c[i-1][j-1]);
}
for (rr int t=iut();t;--t){
rr int n=iut(),a=iut(),b=iut();
print(1ll*stir[n-1][a+b-2]*c[a+b-2][a-1]%mod),putchar(10);
}
return 0;
}