卡特兰数是组合数学中,很经典的一类问题,一般可以解决一下问题
- n个左括号和n个右括号组成的合法括号序列的数量为 Cat(n);
- 1,2,3,……,n 经过一个栈,形成的合法出栈序列的数量为 Cat(n);
- n 个节点构成的不同二叉树的数量为 Cat(n);
- 在平面直角坐标系上,每一步只能向上走或向右走,从 (0,0) 走到 (n,n) 并且除两个端点外不接触直线 y = x的路线数量为 2Cat(n-1);
- 给定n个0和n个1,它们按照某种顺序排成长度为2n的序列,满足任意前缀中0的个数都不少于1的个数的合法序列的个数
知道了这么多,那么卡特兰数应该怎么求呢?
Cat(n) = C(2n,n) / (n+1)
上面就是求卡特兰数的公式。
我们的问题就转化为了求组合数。
组合数可以直接用快速幂求分母和分子,再相除。
如以下问题:求C(n,r)的值,并对1e9+7取模。
见下列代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll p=1e9+7;
ll n,r,res,fz,fm;
ll qmi(ll a,ll b)//快速幂a^b%p
{
ll re=1;
while(b)
{
if(b&1) re=(re*a)%p;
b>>=1;
a=(a*a)%p;
}
return re;
}
ll inv(ll a)//求a的逆元
{
return qmi(a,p-2)%p;
}
ll cnt(ll n,ll r)
{
fz=fm=1;
for(ll i=n;i>=n-r+1;i--) fz=(fz*i)%p;
for(ll i=1;i<=r;i++) fm=(fm*i)%p;
return (fz*inv(fm))%p;
}
int main()
{
cin>>n>>r;
cout<<cnt(n,r)<<endl;
return 0;
}