递推打表求乘法逆元
- 目的:得到在(mod m)的意义下的[2, n)区间内每个数分别对应的逆元
- 推导出递推表达式:
- 任取一个同余式 a x ≡ c ( m o d m ) ax \equiv c(mod m) ax≡c(modm)消去a与c,得到x关于m的式子即为递推表达式
- 对于这个同余式,一定存在一个数y使得 a x − c = m y ax - c = my ax−c=my
- 根据定义 c ∗ ( c 的 逆 元 ) ≡ 1 ( m o d m ) c * (c的逆元) \equiv 1(mod m) c∗(c的逆元)≡1(modm)
- 我们把c的逆元放在inv数组里,所以 c ∗ i n v [ c ] ≡ 1 ( m o d m ) c * inv[c] \equiv 1(mod m) c∗inv[c]≡1(modm)
- 将 c 替换为 a x − m y ax - my ax−my, ( a x − m y ) ∗ i n v [ c ] ≡ 1 ( m o d m ) (ax - my) * inv[c] \equiv 1(mod m) (ax−my)∗inv[c]≡1(modm)
-
a
x
∗
i
n
v
[
c
]
−
m
y
∗
i
n
v
[
c
]
≡
1
(
m
o
d
m
)
ax * inv[c] - my * inv[c] \equiv 1(mod m)
ax∗inv[c]−my∗inv[c]≡1(modm)
- 由于 m y % m = 0 my \% m = 0 my%m=0
- 而原式等价于 ( a x ∗ i n v [ c ] ) % m − ( m y ∗ i n v [ c ] ) % m = 1 (ax * inv[c]) \% m - (my * inv[c]) \% m = 1 (ax∗inv[c])%m−(my∗inv[c])%m=1
- 所以等价于 ( a x ∗ i n v [ c ] ) % m = 1 (ax * inv[c]) \% m = 1 (ax∗inv[c])%m=1
- 所以
a
x
∗
i
n
v
[
c
]
≡
1
(
m
o
d
m
)
ax * inv[c] \equiv 1(mod m)
ax∗inv[c]≡1(modm)
- 在 a x − c = m y 中 , a = m y / x ; − c = m y % x ax - c = my 中,a = my / x;-c = my \% x ax−c=my中,a=my/x;−c=my%x
- m y / x ∗ x ∗ i n v [ − m y % x ] ≡ 1 ( m o d m ) my / x * x * inv[-my \% x] \equiv 1(mod m) my/x∗x∗inv[−my%x]≡1(modm)
- 对于任意的y都满足此式,不妨取y = -1
- − m / x ∗ i n v [ m % x ] ∗ x ≡ 1 ( m o d m ) -m / x * inv[m \% x] * x \equiv 1(mod m) −m/x∗inv[m%x]∗x≡1(modm)
- 在(mod m)的意义下, − m / x ∗ i n v [ m % x ] -m / x * inv[m \% x] −m/x∗inv[m%x]是x的逆元
- 为保证求得结果都为正数, ( m − m / x ) ∗ i n v [ m % x ] (m - m / x) * inv[m \% x] (m−m/x)∗inv[m%x]
- 所以在(mod m)的意义下, ( m − m / x ) ∗ i n v [ m % x ] (m - m / x) * inv[m \% x] (m−m/x)∗inv[m%x]是x在区间[0, m)内的逆元
#include<cstdio>
int inv[100001];
int mod = 9973;
//在(mod 9973)的意义下,[2, 10000)分别对应的逆元
void Inv() {
inv[1] = 1;
for (int i = 2; i < 10000; i++)
inv[i] = (mod - mod/i) * inv[mod % i] % mod;
}
int main()
{
Inv();
for (int i = 0; i < 20; i++)
printf("%d ", inv[i]);
return 0;
}