快速求排列组合 lucas定理

本文介绍了一种高效计算大数组合C(n,m)mod p的方法,特别是当n、m、p非常大且p为素数时。通过Lucas定理及其改进算法,实现了快速计算,并提供具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

对于C(n, m) mod p。这里的n,m,p(p为素数)都很大的情况。

就不能再用C(n, m) = C(n - 1,m) + C(n - 1, m - 1)的公式递推了。

 一般lucas定理的p不能大,在1e6以内,一下代码应该可以吧

typedef long long LL;
using namespace std;

LL exp_mod(LL a, LL b, LL p) {
    LL res = 1;
    while(b != 0) {
        if(b&1) res = (res * a) % p;
        a = (a*a) % p;
        b >>= 1;
    }
    return res;
}

LL Comb(LL a, LL b, LL p) {
    if(a < b)   return 0;
    if(a == b)  return 1;
    if(b > a - b)   b = a - b;

    LL ans = 1, ca = 1, cb = 1;
    for(LL i = 0; i < b; ++i) {
        ca = (ca * (a - i))%p;
        cb = (cb * (b - i))%p;
    }
    ans = (ca*exp_mod(cb, p - 2, p)) % p;
    return ans;
}

LL Lucas(int n, int m, int p) {
     LL ans = 1;

     while(n&&m&&ans) {
        ans = (ans*Comb(n%p, m%p, p)) % p;
        n /= p;
        m /= p;
     }
     return ans;
}

  上面是在线的算法,如果数字小还可以用以下写法

void pre()  //i表示n,j表示m
{
    C[1][0]=C[1][1]=1;
    for(int i=2;i<=1000;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=1000;j++)
          C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    }
    return;
}

 

转载于:https://www.cnblogs.com/stepping/p/7228378.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值