链接:https://www.nowcoder.com/acm/contest/71/D
来源:牛客网
第一行一个正整数T,表示数据组数。(1<=T<=10000) 对于每组数据包含一行三个正整数n,m,k。
题解:进栈出栈问题是组合数学课程中所讲的经典卡特兰数问题之一,其余的还有:
(1)n个左括号,m个右括号的合法组合
(2)n个节点构成的二叉树,共有多少种情形?
(3)买票找零(一开始柜台没零钱)
(4)n*n棋盘从左下角走到右上角而不穿过主对角线的走法
(5)求一个凸多边形区域划分成三角形区域的方法数?
(6)矩阵连乘的括号化
(7)在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
(8)一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列
这些问题都可以用卡特兰数公式求解,具体证明略。。
对于本题,明显的卡特兰数,对于前m个数,对于当前任意一个元素之前的操作,一定是进栈大于等于出栈,对于当前元素后边的元素则一定是出栈大于等于进栈,两者相乘即为答案。。。
一般公式:ans=C(n+m,n)-C(n+m,n+1).....
#include
#define maxn 2000005
#define mod 1000000007
#define ll long long
ll fac[maxn],inv[maxn],n,m,k;
ll q(ll x,ll y)
{
ll res=1ll;
while(y)
{
if(y%2)
res=res*x%mod;
x=x*x%mod;
y/=2;
}
return res;
}
ll C(ll x,ll y)
{
if(y<0 || y>x) return 0;
return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
}
ll cal(ll x,ll y)
{
return (C(x+y,x)-C(x+y,x+1)+mod)%mod;
}
int main(void)
{
int T;
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(ll i=2;i<=maxn-5;i++)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=q(fac[i],mod-2);
}
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&k);
printf("%lld\n",cal(m-1,m-k)*cal(n-(m-k),n-m)%mod);
}
return 0;
}