链接:https://www.nowcoder.com/acm/contest/71/D
来源:牛客网
题目描述
WYF正试图用一个栈来构造一棵树,现在他已经构造了n个元素作为树的节点,只要将这n个元素依次入栈出栈就可以形成一棵树了。当然,这个问题与树并没有关系,所以它叫做WYF的栈。每次你可以入栈一个新元素或者当栈非空时出栈一个元素,n个元素必须依次入栈,而WYF希望其中第m个元素入栈之后,栈中恰好有k个元素,现在他想知道一共有多少种入栈出栈顺序满足这个条件。
输入描述:
第一行一个正整数T,表示数据组数。(1<=T<=10000) 对于每组数据包含一行三个正整数n,m,k。
输出描述:
对于每组数据输出一个正整数表示答案。由于答案可能过大,所以只需要输出对10 9+7取模后的答案
其实题目就是让你求一个01序列满足:
①总共n个1,n个0(相当于进栈和出栈);
②对于所有前缀1的个数一定要大于等于0的个数;
③额外的限制条件:在某个前缀一定满足有刚好m-1个1和m-k个数字0
如果只有前两个条件,答案刚好就是第n项卡特兰数
其实看第②③个条件,可以得出
④对于所有后缀0的个数一定要大于等于1的个数;
⑤在某个后缀一定满足有刚好n-(m-k)个数字0,n-m个数字1
如果某个前缀一定要满足刚好有a个1和b个0,并且所有的前缀1的个数一定要大于等于0的个数,情况总数为
所以这题答案就是(条件②③)*(条件④⑤)
#include<stdio.h>
#define LL long long
#define mod 1000000007
LL Pow(LL a, LL b);
LL C(LL m, LL n);
LL Lucas(LL m, LL n);
LL Fan(LL n, LL m);
LL inv[2000005] = {1}, jc[2000005] = {1};
int main(void)
{
LL T, m, n, k, i;
for(i=1;i<=2000001;i++)
jc[i] = (jc[i-1]*i)%mod;
inv[2000001] = Pow(jc[2000001], mod-2);
for(i=2000000;i>=1;i--)
inv[i] = inv[i+1]*(i+1)%mod;
scanf("%d", &T);
while(T--)
{
scanf("%lld%lld%lld", &n, &m, &k);
printf("%lld\n", Fan(m-1, m-k)*Fan(n-(m-k), n-m)%mod);
}
return 0;
}
LL Fan(LL n, LL m)
{
LL all;
all = n+m;
return (C(all, n)-C(all, n+1)+mod)%mod;
}
LL Pow(LL a, LL b)
{
LL ans;
ans = 1;
while(b)
{
if(b%2==1)
ans = (ans*a)%mod;
a = (a*a)%mod;
b /= 2;
}
return ans;
}
LL C(LL n, LL m)
{
LL ans;
if(n<m)
return 0;
ans = jc[n]*inv[m]%mod*inv[n-m]%mod;
return ans;
}