组合数的多种求法 7.18

1. 杨辉三角(递推法)

时间复杂度:O( n * n )

C(n, k) = C(n - 1, k - 1) + C(n - 1, k)

预处理: C(n, 0) = 1,每一列第一个数=1,从a[0][0]开始

例题C-前缀平方和序列_牛客小白月赛97 (nowcoder.com)

代码
#include<iostream>

using namespace std;

typedef long long ll;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)

const int mod = 1e9 + 7, N = 1e3 + 10;
ll ans,cnt, n, x, a[N][N];

int main()
{
    IOS;
    cin >> n >> x;
    while((cnt + 1) * (cnt + 1) <= x) cnt++;
    a[0][0] = 1;
    for(int i = 1; i <= cnt; i++)
    {
        a[i][0] = 1;
        for(int j = 1; j <= i; j++) 
            a[i][j] = (a[i-1][j-1] + a[i-1][j]) % mod;
    }    
    cout<<a[cnt][n]<<endl;
    
    return 0;
}

2.乘阶逆元 (费马小定理)

通常和快速幂绑定在一起,是最快的做法

时间复杂度:O( n * log(n) )

预处理乘阶和乘阶的逆元

讲解费马小定理

快速幂

核心在于将指数的乘法分解为一系列的平方和乘法操作,从而减少计算的次数,

提高计算 pow(a, b ) mod  𝑚 的效率,特别是当 b 非常大时

快速幂和费马小定理的联系

利用费马小定理,可以减少快速幂算法中指数的大小,只要mod是质数,且a不被mod整除,则用 b mod  (𝑝−1) 替换 b

求逆元

在模运算中,通常没有直接的除法操作,因为模运算的定义是基于整数除以一个数后的余数。逆元允许我们在模 𝑚m 的系统中执行除法操作。

计算阶乘时,直接计算阶乘可能会导致大数溢出。通过使用逆元,我们可以将组合数的计算转换为

计算C(n, k)组合数的代码
#include<iostream>
using namespace std;

typedef long long ll;

const int N = 1e5 + 10, mod = 1e9 + 7;

ll fact[N],nifact[N];
ll quick_mi(ll a, ll k)
{
    ll ans = 1;
    a %= mod;
    while(k){
        if(k & 1) {
            ans = (ans * a) % mod;
        }
        a = (a * a) % mod;
        k >>= 1;
    }
    return ans;
}

int main() {
    int n,k;
    cin>>n>>k;

    fact[0] = nifact[0] = 1;
    for(int i = 1; i < N; i ++) 
        fact[i] = fact[i - 1] * i % mod; //求阶乘

    nifact[N-1] = quick_mi(fact[N-1], mod - 2) % mod;
    for(int i = N-2; i >= 0; i --) {
        nifact[i] = nifact[i + 1] * (i + 1) % mod;
    }
    ll sum = fact[n] * nifact[k] % mod * nifact[n-k] % mod;
    cout<<sum;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值