Wannafly挑战赛9-D-造一造(卡特兰数)

题目描述

WYF正试图用一个栈来构造一棵树,现在他已经构造了n个元素作为树的节点,只要将这n个元素依次入栈出栈就可以形成一棵树了。当然,这个问题与树并没有关系,所以它叫做WYF的栈。每次你可以入栈一个新元素或者当栈非空时出栈一个元素,n个元素必须依次入栈,而WYF希望其中第m个元素入栈之后,栈中恰好有k个元素,现在他想知道一共有多少种入栈出栈顺序满足这个条件。

链接:https://www.nowcoder.com/acm/contest/71/D
来源:牛客网

输入描述:

第一行一个正整数T,表示数据组数。(1<=T<=10000)
对于每组数据包含一行三个正整数n,m,k。

输出描述:

 
对于每组数据输出一个正整数表示答案。
 由于答案可能过大,所以只需要输出对10 9+7取模后的答案

题解:进栈出栈问题是组合数学课程中所讲的经典卡特兰数问题之一,其余的还有:

(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<stdio.h>
#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;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值