线性递推求逆元

Published on7/29/2025
Created on 12/17/2021

这道题中:P3811 【模板】乘法逆元 - 洛谷

要求模 pp 意义下 11nn 所有整数的逆元,我们可以采用以下方法:

假设我们现在要求 i1i^{-1} : 设 p=qi+rp=qi+r ,其中 qqrr 为整数,即为 ppii 的商和余数。有 q=piq=\lfloor\frac{p}{i}\rfloorr=p % ir=p\ \%\ i 。 显然有

qi+rp0(mod p) qi+r\equiv p\equiv0\quad(\mathrm{mod}\ p)

同余式两边同乘 i1r1i^{-1}r^{-1}

qr1+i10(mod p) qr^{-1}+i^{-1}\equiv0\quad(\mathrm{mod}\ p)

移项,再代入:

i1qr1(mod p)i1pi(p % i)1(mod p) \begin{aligned} i^{-1}&\equiv-qr^{-1}&(\mathrm{mod}\ p)\\ i^{-1}&\equiv- \lfloor\frac{p}{i}\rfloor(p\ \%\ i)^{-1} &(\mathrm{mod}\ p) \end{aligned}

由于 p % i<ip\ \%\ i<i ,我们肯定先前求过,用一个 Inv[]\mathtt{Inv[]} 数组来记录每个数的逆元,递推时直接检索即可。 同时我们要保证同余式右侧大于零,按照[[EXGCD]]中求不定方程最小非负整数解的方法即可:

Inv[ i ]=(piInv[ p % i ] % p+p) % p \mathtt{Inv[}\ i\ \mathtt{]} =(-\lfloor\frac{p}{i}\rfloor \mathtt{Inv[}\ p\ \%\ i\ \mathtt{]} \ \%\ p+p)\ \%\ p

递推起点是 Inv[ 1 ]=1\mathtt{Inv[}\ 1\ \mathtt{]}=1 ,当然循环要从 22 开始,题目保证了 p>np>n 且为质数,故无需考虑 p % i=0p\ \%\ i=0 的情况。

时间复杂度为 O(n)\mathrm{O}(n)

参考代码:

#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
//---//
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

typedef unsigned int u;
typedef long long ll;
typedef unsigned long long llu;

#define rep(i, a, b) for (ll i = a; i < b; i++)
#define REP(i, a, b) for (ll i = a; i <= b; i++)
#define per(i, b, a) for (ll i = b; i >= a; i--)

const ll N = 3000005;

ll inv[N];

signed main() {
  ll n, p;
  scanf("%lld%lld", &n, &p);
  REP(i, 1, n)
  printf("%lld\n", inv[i] = i - 1 ? (-p / i * inv[p % i] % p + p) % p : 1);
}

// https://www.luogu.com.cn/record/60969822