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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/haut_ykc/article/details/79426135

题目描述

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

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

输入描述:

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

输出描述:

对于每组数据输出一个正整数表示答案。
 由于答案可能过大,所以只需要输出对109+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;
}

展开阅读全文

没有更多推荐了,返回首页