卡特兰数简要原理及组合数实现

博客介绍了卡特兰数的定义及其在排列问题中的应用,通过转换为路径问题来计算。它给出了从(0,0)到(n,n)的路径中不越过y=x线的路径数量,并通过减去非法路径数来求得结果。文中还提供了组合数的递归实现,并考虑了数据较大的情况,使用模逆元避免溢出。此外,展示了快速幂模板用于计算逆元。

卡特兰数就结论来说是指从1到n所有数经过入栈和出栈后得到的排列的种类数,值为 C(2n,n)/(n+1)

原理:将其转换为从(0,0)点到(n,n)点的路径数中不越过 y=x 线的路径数,用所有的路径数减去非法路径数,

每条非法路径都会经过y=x+1这条线,将其经过 y=x+1 这条线后的路径对这条线作对称,

发现它的终点会落在点(n-1,n+1)上,每条非法路径都能通过这样的变化转为以(n-1,n+1)为终点的一条路径,反过来,每一条以(n-1,n+1)为终点的路径也能转化为一条以(n,n)为终点的非法路径,所以非法路径数就是从原点到(n-1,n+1)的路径数,即C_{2n}^{n-1}

所以最终结果就是总路径数 C_{2n}^n 减去非法路径数 C_{2n}^{n-1} 化简得到 \frac{C_{2n}^{n}}{(n+1) }

组合数实现:

C_{n}^{m} = C_{n-1}^{m-1}+C_{n-1}^{m}

long long c[N][N];
long long C(int x,int y)
{
    if(c[x][y]!=-1)return c[x][y];
    if(y>x)return c[x][y]=0;
    if(y==0)return c[x][y]=1;
    if(x==y)return c[x][y]=1;
    return c[x][y]=C(x-1,y-1)+C(x-1,y);
}

 数据较大时使用C_{n}^{m}=\frac{n!}{m!(n-m)!}实现,注意除法使用逆元

const int N = 1e5+10;
const int Mod = 1e9+7;
int jc[N], fjc[N];

int gmi(int a, int b = Mod - 2)      //逆元(快速幂模板)
{
    if (a == 0 || a == 1)
        return a;
    int res = 1, t = a;
    while (b)
    {
        if (b & 1)
            res = res * t % Mod;
        b >>= 1;
        t = t * t % Mod;
    }
    return res;
}
inline int C(int x, int y)
{
    if(x < y)return 0;
    return jc[x] * fjc[x - y] % Mod * fjc[y] % Mod;
}
void init()
{
    jc[0] = 1;
    for (int i = 1; i < N; i++)
        jc[i] = i * jc[i - 1] % Mod;
    fjc[N - 1] = gmi(jc[N - 1]);
    for (int i = N - 1; i >= 0; i--)
        fjc[i] = fjc[i + 1] * (i + 1) % Mod;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值