题面
https://www.luogu.org/problem/P4609
题解:首先注意到整个“建筑群”被最高的建筑分成两部分,两部分相对独立。
把第一类斯特林数的环变成强制以最大值为头的序列,这样一个盒子代表了一个楼房和被它遮盖的楼房的集合。
所以只要有$a+b-2$个这样的集合,然后把其中的$a-1$个分给左侧,$b-1$个分给右侧就可以了。
为什么不组合数不乘在楼房数上?因为我只考虑了一个斯特林数。
- 第一类斯特林数的递推边界条件:$S1[0][0]=1$($i$,$j$都从$1$开始),我的写法是左小右大,在$i$>$j$时,$S1[i][j]=0$。
- 杨辉三角形处理组合数的时候,注意我通常的写法是左边大右边小的,如果调出来发现答案是$0$,可以看看是不是这里写错了。
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define mod 1000000007 #define LL long long #define ri register int using namespace std; inline int read() { int ret=0,f=0; char ch=getchar(); while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0' && ch<='9') ret*=10,ret+=ch-'0',ch=getchar(); return f?-ret:ret; } int T,n,a,b; int s1[250][50500],c[250][250]; int main() { T=read(); s1[0][0]=1; for (ri i=1;i<=230;i++) for (ri j=1;j<=50050;j++) s1[i][j]=(s1[i-1][j-1]+(s1[i][j-1]*1LL*(j-1))%mod)%mod; c[0][0]=1; for (ri i=1;i<=230;i++) for (ri j=0;j<=i+1;j++) c[i][j]=(((j==0)?0:c[i-1][j-1])+c[i-1][j])%mod; while (T--) { n=read(); a=read(); b=read(); printf("%d ",(s1[a+b-2][n-1]*1LL*c[a+b-2][a-1])%mod); } return 0; }