线性求逆元
P3811 【模板】模意义下的乘法逆元
题目背景
这是一道模板题。
题目描述
给定正整数 \(n,p\),求 \([1,n]\) 中所有整数在模 \(p\) 意义下的乘法逆元。
\(a\) 模 \(p\) 的乘法逆元定义为 \(ax\equiv1\pmod p\) 的解。
输入格式
一行两个正整数 \(n,p\)。
输出格式
输出 \(n\) 行,其中第 \(i\) 行表示 \(i\) 在模 \(p\) 下的乘法逆元。
输入输出样例 #1
输入 #1
10 13
输出 #1
1
7
9
10
8
11
2
5
3
4
说明/提示
所有数据满足 $ 1 \leq n \leq 3 \times 10 ^ 6\(,\)n < p < 20000528 $。
输入保证 $ p $ 为质数。
线性求逆元算法可以在 \(O(n)\) 的时间复杂度内,求出 \(1 \sim n\) 中所有数在模 \(p\) 意义下的乘法逆元(前提是 \(p\) 为质数)。这在算法竞赛中处理大量组合数取模等问题时非常常用。核心公式推导要求 \(i\) 在模 \(p\) 意义下的逆元 \(inv[i]\)。首先,将 \(p\) 表示为带余除法的形式:$$p = k \cdot i + r$$其中商 \(k = \lfloor p/i \rfloor\),余数 \(r = p \bmod i\)。将上式放到模 \(p\) 的意义下,显然有:$$k \cdot i + r \equiv 0 \pmod p$$等式两边同时乘上 \(i^{-1} \cdot r^{-1}\)(即 \(inv[i] \cdot inv[r]\)):$$k \cdot r^{-1} + i^{-1} \equiv 0 \pmod p$$移项得到 \(i^{-1}\):$$i^{-1} \equiv -k \cdot r^{-1} \pmod p$$将 \(k\) 和 \(r\) 替换回原来的表达式:$$inv[i] \equiv -\lfloor p/i \rfloor \cdot inv[p \bmod i] \pmod p$$代码实现优化:在 C++ 中,直接使用负数取模可能会得到负数结果。为了保证结果为正数,通常将 \(-\lfloor p/i \rfloor\) 替换为 \((p - \lfloor p/i \rfloor)\),即:$$inv[i] = (p - \lfloor p/i \rfloor) \cdot inv[p \bmod i] \bmod p$$
通过代码
#include <iostream>
#include <algorithm>
using namespace std;
using i64 = long long;
i64 t;
i64 a[3000005],b[3000005];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
i64 p;
cin >> t>>p;
a[1] = 1;
for (i64 i = 2; i <= t; i++) {
a[i] = (p - p / i) * a[p % i] % p;
}
for (i64 i = 1; i <= t; i++) {
cout << a[i] <<'\n';
}
}

浙公网安备 33010602011771号