线性求逆元

本文介绍了线性求逆元的原理与递推公式。通过数学推导展示如何利用p=k*i+r的形式来求解i的逆元,并给出具体的递推公式A[i]=-(p/i)*A[p%i]。此外,还提到了可以通过递归方式计算单个数的逆元。

#线性求逆元

  1. 1−1≡1(mod p)1^{-1}\equiv1(mod\ p)111(mod p)
  2. p=k∗i+r,r<i,1<i<pp=k*i+r,r<i,1<i<pp=ki+r,r<i,1<i<p
  3. k∗i+r≡0(mod p)k*i+r \equiv 0 (mod\ p)ki+r0(mod p)
  4. 两边同事乘上i−1∗r−1i^{-1}*r^{-1}i1r1得到
  5. k∗r−1+i−1≡0(mod p)k*r^{-1}+i^{-1}\equiv0 (mod\ p)kr1+i10(mod p)
  6. i−1≡−k∗r−1(mod p)i^{-1}\equiv-k*r{-1}(mod \ p)i1kr1(mod p)
  7. i−1≡−∣pi∣∗(pmodi)−1(mod p)i^{-1}\equiv-|\frac{p}{i}|*(p\quad mod\quad i)^{-1}(mod\ p)i1ip(pmodi)1(mod p)
  8. 所以递推公式为
  9. A[i]=−(p/i)∗A[p%i]A[i]=-(p/i)*A[p \% i]A[i]=(p/i)A[p%i]
  10. 同时也可以用log(p)次计算出单个数的逆元,-----用递归的方式求需要计算的元素即可
<think>好的,用户想查找关于线性求逆元和求组合数的文章,并获取正确的代码实现。首先,我需要回忆一下线性求逆元的常见方法,通常有两种方式:一种是使用费马小定理,另一种是递推公式。但用户提到的是线性求逆元,所以应该是指递推法,时间复杂度O(n),适合预处理大量逆元的情况。 然后,组合数的计算通常需要阶乘和阶乘逆元的预处理,这样可以在O(1)时间内得到组合数的值。用户可能希望得到这两个步骤的代码实现,包括如何线性求逆元,如何计算阶乘逆元,以及如何组合这些来得到组合数。 接下来,我需要参考用户提供的引用。引用[2]中提到可以通过线性求逆元求阶乘逆元,使用循环将逆元逐次相乘得到阶乘的逆元。引用[3]则解释了逆元在组合数计算中的作用,用于将除法转换为乘法,避免除法取模的问题。 因此,正确的步骤应该是: 1. 预处理逆元数组inv,其中inv[i]表示i的逆元,使用递推公式inv[i] = (mod - mod/i) * inv[mod%i] % mod。 2. 预处理阶乘数组fact和阶乘逆元数组fact_inv,其中fact[i] = i! % mod,fact_inv[i] = (i!)^{-1} % mod。 3. 组合数C(n,m)的计算公式为fact[n] * fact_inv[m] % mod * fact_inv[n-m] % mod。 代码实现方面,需要先处理逆元数组,然后处理阶乘和阶乘逆元。用户可能需要Rust代码,但根据示例中的Python代码,可能需要用其他语言?不过用户引用中有提到Rust,所以可能倾向于Rust实现。不过用户没有明确说明语言,可能希望通用代码或者Rust。但根据用户的问题描述,正确代码实现是关键,所以需要确保代码正确无误,并符合线性求逆元的方法。 另外,需要注意模数mod的选择,通常是一个大质数,比如1e9+7。在代码中需要预先定义。同时,处理边界条件,比如inv[0]和inv[1]的处理,以及fact[0]初始化为1等。 现在需要将这些步骤整理成结构清晰的回答,包括算法描述、复杂度分析、应用,以及模板代码。同时,用户可能需要相关的问题,如如何应用在组合数计算中,或者优化方法等。 可能的问题包括: 1. 线性求逆元的原理是什么? 2. 如何验证逆元计算的正确性? 3. 组合数计算的时间复杂度是多少? 4. 如何处理大模数下的组合数计算? 需要确保代码正确,例如在Rust中实现线性逆元,然后计算阶乘和阶乘逆元,最后组合数。同时,检查是否有错误,比如递推公式是否正确,数组索引是否从1开始或0开始。 最后,用户可能需要参考链接或更多例题,但根据用户的要求,正确代码和整理的文章结构是关键。需要确保引用标记正确,引用的内容是否相关,比如引用[2]中的阶乘逆元部分,引用[3]中的逆元在组合数的应用。</think>### 线性求逆元与组合数计算详解 #### 一、算法原理 1. **线性求逆元** 对于质数模数$p$,通过递推公式求1~n的逆元数组$inv$: $$inv[i] = (p - \lfloor p/i \rfloor) \cdot inv[p\ mod\ i]\ mod\ p$$ 边界条件$inv[1]=1$,时间复杂度$O(n)$[^2]。 2. **阶乘逆元预处理** 计算$i!$的逆元$fact\_inv[i]$,利用逆元的积性性质: $$fact\_inv[i] = fact\_inv[i+1] \cdot (i+1)\ mod\ p$$ 或通过线性逆元数组累乘得到[^2]。 3. **组合数计算** 预处理阶乘数组$fact$和$fact\_inv$后,组合数公式为: $$C(n,m) = fact[n] \cdot fact\_inv[m] \cdot fact\_inv[n-m]\ mod\ p$$ #### 二、模板代码实现(Rust) ```rust const MOD: usize = 1_000_000_007; const MAX_N: usize = 1e6 as usize; // 根据需求调整 fn main() { // 1. 线性求逆元 let mut inv = vec![1; MAX_N + 1]; for i in 2..=MAX_N { inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD; } // 2. 预处理阶乘及阶乘逆元 let mut fact = vec![1; MAX_N + 1]; let mut fact_inv = vec![1; MAX_N + 1]; for i in 1..=MAX_N { fact[i] = fact[i-1] * i % MOD; fact_inv[i] = fact_inv[i-1] * inv[i] % MOD; } // 3. 组合数查询函数 fn comb(n: usize, m: usize, fact: &[usize], fact_inv: &[usize]) -> usize { if m > n { return 0; } fact[n] * fact_inv[m] % MOD * fact_inv[n - m] % MOD } } ``` #### 三、复杂度分析 | 步骤 | 时间复杂度 | 空间复杂度 | |--------------------|------------|------------| | 线性求逆元 | O(n) | O(n) | | 阶乘预处理 | O(n) | O(n) | | 单次组合数查询 | O(1) | O(1) | #### 四、常见应用场景 1. 排列组合类计数问题(如卡特兰数) 2. 二项式系数计算 3. 概率论中的组合概率计算 4. 容斥原理实现[^3] #### 五、优化技巧 1. **多组查询时预处理**:预处理后单次查询时间复杂度为O(1) 2. **内存优化**:复用逆元数组减少内存占用 3. **延迟计算**:动态扩展预处理范围应对未知数据规模
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值