题目:http://acm.hdu.edu.cn/showproblem.php?pid=4372
刨去最高的,剩下的就是 x+y-1 个块。一个块如果已知取哪些数,则最左(右)边是哪个数已经确定,剩下的位置随便排列;其实就是一个圆排列,每个排列从最大元素旁边断成链。
所以就是 n-1 个数分成 x+y-2 个圆排列,即第一类斯特林数。再乘上 x+y-2 个里选 x-1 个放在最高点左边的方案数即可。
注意 x+y-1 可能大于 n 。本来斯特林数的那个位置是0,可以不用特判,但可能爆数组!所以开大数组或者特判。
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=4005,mod=1e9+7; int T,n,s[N][N],c[N][N]; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } void upd(int &x){x>=mod?x-=mod:0;} void init() { int lm=2000; s[0][0]=1; for(int i=1;i<=lm;i++) for(int j=1;j<=i;j++) s[i][j]=(s[i-1][j-1]+(ll)s[i-1][j]*(i-1))%mod; for(int i=0;i<=lm;i++)c[i][0]=1; for(int i=1;i<=lm;i++) for(int j=1;j<=i;j++) c[i][j]=c[i-1][j-1]+c[i-1][j],upd(c[i][j]); } int main() { init();T=rdn(); while(T--) { n=rdn();int x=rdn(),y=rdn(); /* if(x+y-1>n)puts("0"); else */printf("%lld ",(ll)s[n-1][x+y-2]*c[x+y-2][x-1]%mod); } return 0; }