以下 \(p\) 为模数,\(x\) 为我们要求逆元的数。
最直接的是利用费马小定理,\(x^{-1}\equiv x^{p-2}(mod\ p)\)是,时间复杂度:\(\mathcal {O}(nlog_2(n))\)。
这里有两个线性做法:
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <bitset> #define uint unsigned int #define LL long long using namespace std; const int MAXN = 3e6 + 5; int n, p; LL dp[MAXN]; // 令 p = ax+b, 则 ax+b=0(mod p) // (ax+b)/(bx)=0(mod p) // a*b^(-1)+x^(-1)=0 -> x^(-1)=-(p/x)/(p%x) -> dp[x]=-(p/x)*dp[p%x] int main() { scanf("%d%d", &n, &p); dp[1] = 1; for(int i = 2; i <= n; i ++) dp[i] = -(p / i * dp[p % i]), dp[i] = (dp[i] % p + p) % p; for(int i = 1; i <= n; i ++) printf("%lld\n", dp[i]); return 0; }
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <bitset> #define uint unsigned int #define LL long long using namespace std; const int MAXN = 3e6 + 5; int inv[MAXN], prime[MAXN / 10], tot; bitset <MAXN> vis; int n, p; int Quick_Pow(int x, int y) { int ans = 1; for(; y; y >>= 1) { if(y & 1) ans = (LL)ans * x % p; x = (LL)x * x % p; } return ans; } void Prime() { inv[1] = 1; for(int i = 2; i <= n; i ++) { if(!vis[i]) prime[++ tot] = i, inv[i] = Quick_Pow(i, p - 2); for(int j = 1; j <= tot && i * prime[j] <= n; j ++) { vis[i * prime[j]] = 1; inv[i * prime[j]] = (LL)inv[i] * inv[prime[j]] % p; if(i % prime[j] == 0) break; } } } int main() { scanf("%d%d", &n, &p); Prime(); for(int i = 1; i <= n; i ++) printf("%d\n", inv[i]); return 0; }