卡特兰数

先上一个比较快O(n)的模板,n的范围是1e6

#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <algorithm>
#define ULL unsigned long long
using namespace std;

long long n;
const long long M=1000000007;
long long inv[1000010];
long long last,now=1;

void init()
{
    inv[1]=1;
    for(int i=2;i<=n+1;i++)inv[i]=(M-M/i)*inv[M%i]%M;
}

int main()
{
    scanf("%lld",&n);
    init();
    for(int i=2;i<=n;i++)
    {
        last=now;
        now=last*(4*i-2)%M*inv[i+1]%M;
    }
    printf("%lld\n",last);
    return 0;
}
下面来说它可以求什么样的问题:

1)出栈次序问题


1】n个数有多少种不同的进出栈顺序?


2】n辆火车有多少种不同进出站顺序?



2)加括号问题


1】n对括号有多少种匹配方式?


2】n+1个数相乘,有多少种乘法顺序?(要加n对括号)




3)二叉树问题 


1】给定n个节点,能构成多少种不同的二叉树?


转化思路:二叉树的递归问题直接满足catalan数的递推公式。



4)排队顺序问题  


1】长度为2n的Dyck words有多少种?(Dyck words是由n个X和n个Y组成的字符串,其有一个特点:从左往右,对X和Y分别计数,Y的个数始终不大于X的个数。)

转化思路: 可以把X看作入栈,Y看作出栈,Y的个数始终不大于X的个数这一性质正好和空栈无法再出栈相一致,所以Dyck words就等价为出入栈序列。


1.1】2n个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?

转化思路: 2n个人先从矮到高排序,然后挨个被选到第一排或者第二排,如果要满足题意,当且仅当每挑选完一次之后,第二排中的人数不多于第一排中的人数。


1.2】在一个2*n的格子中填入1到2n这些数值,使得每个格子内的数值都比其右边和上边的所有数值都小,有多少种填法?


1.3】有2n个人排成一行进入剧场。入场费5元。其中n个人只有5元钞票,n个人只有10元钞票(必须找零),剧院无其它钞票,问有多少种买票顺序能让每个人都顺利买票?

转化思路: 每来一个5元的人,就能满足1个10元的人,所以始终要满足10元的人数不多于5元的人数。




5)正方形网格路径问题


1】对于一个n*n的正方形网格,每次我们能向右或者向上移动一格,求从左下角到右上角的所有在副对角线右下方的路径总数。

转化思路: 把一条水平边标记为+1,垂直边标记为-1,那么就组成一个n个+1和n个-1的序列,我们所要保证的是前k步中水平边的个数不小于垂直边的个数。


1.1】一位大城市的律师在他住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果他从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?




6)将多边形划分问题


1】n+2条边的凸多边形能划分成n个三角形,有多少种划分方法?

转化思路: 首先知道需要加n-1条弦。这里以边为研究对象,一共有n+2条边。加弦的目的是把两个挨着的边括起来。那么这就成了在两个边两侧加括号了,n+2条边要加n对括号。


2】n层阶梯划分为n个矩形,一共有多少种分法?


2】圆桌周围有2n个人,他们两两握手,但没有交叉的方案数。(每个人最多握一次手)

转化思路: 握手行为是由2个人共同完成的,设定这一行为有主动方(入栈)和被动方(出栈),假设握手行为是根据座次号(1-2n)按时间顺序发生的,如果那人是主动方,他会提出握手要求(+1);如果那人是被动方,他会接受握手要求(-1)。因为握手不能交叉,所以这就成了出入栈序列。

    从没有交叉的图形角度来看,一旦确定了某个握手行为,握手的双方就划分了两个隔离的部分,这两个部分内部再进行握手。


2.1】在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值