题解:
先考虑暴力。把数字从大到小往序列中插,就可以得到一个DP的方法:
f[i][j][k]
f
[
i
]
[
j
]
[
k
]
表示当前插了前
i
i
大的数,左边能看到个,右边能看到
k
k
个,转移显然:。然后考虑放数字的过程,一定要有
A
A
次数字是放到最左边,次数字是放到最右边,剩下的
n−A−B
n
−
A
−
B
次都是插在其它数中间,所以说我们要求的实际上是一个
n!
n
!
除掉某
k
k
个数的乘积后的和,这个是很好递推的,设表示
i!
i
!
去掉
j
j
个数后的和,那么有,听说这个就是第一类斯特林数的递推式,不过不会也没关系,因为我也不会,只要掌握了上述过程,这题就解决了。最后还要乘上一个组合数,表示那些特殊步骤中哪些是放在最左或最右。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=50010;
const int Maxm=210;
const int mod=1000000007;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int S[Maxn][Maxm],C[Maxm][Maxm];
void pre()
{
C[0][0]=1;
for(int i=1;i<=200;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
S[0][0]=1;
LL tmp=1;
for(int i=1;i<=50000;i++)
{
tmp=(LL)tmp*i%mod;
S[i][0]=tmp;
for(int j=1;j<=min(i,200);j++)
S[i][j]=((LL)i*S[i-1][j]%mod+S[i-1][j-1])%mod;
}
}
int main()
{
pre();
int T=read();
while(T--)
{
int n=read(),a=read(),b=read();
if(n==1)
{
if(a==1&&b==1)puts("1");
else puts("0");
}
else if(!a||!b||(a==1&&b==1))puts("0");
else printf("%d\n",(LL)S[n-2][a+b-3]*C[a+b-2][a-1]%mod);
}
}