P3811 【模板】乘法逆元
题目背景
这是一道模板题
题目描述
给定n,p求1~n中所有整数在模p意义下的乘法逆元。
输入输出格式
输入格式:
一行n,p
输出格式:
n行,第i行表示i在模p意义下的逆元。
输入输出样例
说明
1 \leq n \leq 3 \times 10 ^ 6, n < p < 200005281≤n≤3×106,n<p<20000528
输入保证 pp 为质数。
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 3e6 + 10; #define LL long long #define lgj 1000000007 LL jc[N], inv[N], Inv[N]; LL n, k; inline LL read(){ LL x = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x; } void exgcd(LL a, LL b, LL & x, LL & y){ if(!b){ x = 1; y = 0; return ; } exgcd(b, a % b, x, y); LL tmp = x; x = y; y = tmp - a / b * y; } inline void work_1(){ LL x, y; exgcd((jc[k] * jc[n - k]) % lgj, lgj, x, y); while(x < 0) x += lgj; LL answer = (jc[n] * x) % lgj; printf("%lld", answer); exit(0); } inline LL ksm(LL x, LL y){ LL ret = 1; while(y){ if(y & 1) ret = ret * x % lgj; x = x * x % lgj; y >>= 1; } return ret; } inline void work_2(){ LL x = ksm((jc[k] * jc[n - k]) % lgj, lgj - 2); LL answer = (jc[n] * x) % lgj; printf("%lld", answer); exit(0); } inline void work_3(){ inv[1] = inv[0] = 1; Inv[0] = Inv[1] = 1; for(int i = 2; i <= n; i ++) { inv[i] = (1LL * (- (lgj / i)) * inv[lgj % i]) % lgj; if(inv[i] < 0) inv[i] += lgj; Inv[i] = (Inv[i - 1] % lgj * inv[i] % lgj) % lgj; if(Inv[i] < 0) Inv[i] += lgj; } LL answer = ((jc[n] % lgj * Inv[k] % lgj) % lgj * Inv[n - k] % lgj) % lgj; printf("%lld", answer); } inline void work_4(){ inv[1] = inv[0] = 1; for(int i = 2; i <= n; i ++) { inv[i] = ((1LL * (- (k / i))) * inv[k % i]) % k; if(inv[i] < 0) inv[i] += k; } } int main() { n = read(); k = read(); jc[1] = 1; for(int i = 2; i <= n; i ++) jc[i] = (jc[i - 1] * (i % lgj)) % lgj; //work_1();//exgcd //work_2();//ksm //work_3();//线性求逆元 inv[i] i 在 % lgj 意义下的逆, Inv[i] 阶乘的逆,也就是将逆阶乘 work_4(); for(int i = 1; i <= n; i ++) printf("%lld\n", inv[i]); return 0; }