1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
//! 素数 $m$ を法とした逆元のテーブル。
/// 素数 $m$ を法とした逆元のテーブル。
///
/// $\\gdef\\recip#1#2{#1\_{(#2)}\^{-1}}$
/// 以下、$i\^{-1}\\bmod j$ を $\\recip{i}{j}$ と書く。
///
/// 次で定められる \\(a = (a\_0, a\_1, \\dots, a\_n)\\) を返す。
/// \\[
/// a\_i = \\begin{cases}
/// \\recip{i}{m}, & \\text{if }\\recip{i}{m}\\text{ exists}; \\\\
/// 0, & \\text{otherwise}.
/// \\end{cases}
/// \\]
/// Note: $\\recip{i}{m}\\ne 0$。
///
/// # Idea
///
/// 次のことが成り立つ:
/// - $\\recip{0}{m}$ は存在しない。
/// - $\\recip{1}{m} = 1$ である。
///
/// $\\recip{(i+m)}{m} = \\recip{i}{m}$ なので、$i\\lt m$ について考える。
///
/// 各 $j$ ($1\\le j\\lt i$) については $\\recip{j}{m}$
/// が得られているとする。ただし、$m$ が素数なので、これらは常に存在する。
///
/// $m = q\\cdot i+r$ ($0\\le r\\lt i$) とおき、$\\recip{i}{m}$ を辺々掛けると
/// $$
/// \\begin{aligned}
/// m\\cdot\\recip{i}{m} &= q\\cdot i\\cdot\\recip{i}{m} + r\\cdot\\recip{i}{m} \\\\
/// 0 &\\equiv q + r\\cdot\\recip{i}{m} \\pmod{m}.
/// \\end{aligned}
/// $$
/// よって、
/// $$ \\recip{i}{m} \\equiv -q\\cdot\\recip{r}{m} \\pmod{m}. $$
/// $q\\gt 0$ と $\\recip{r}{m}\\gt 0$ であることから、
/// $$ \\recip{i}{m} = m - (q\\cdot\\recip{r}{m} \\bmod m) $$
/// となる。
///
/// $r\\lt i$ より $\\recip{r}{m}$
/// は既に得られているため、$\\recip{i}{m}$ が順次 $O(1)$ time で求まる。
///
/// # Notes
/// 一般のケースでは $\\gcd(r, m)=\\gcd(i, m)$ とは限らないので注意。
/// たとえば、$\\recip{3}{8}$ を求める際、$8 = 3\\cdot 2 + 2$ なので
/// $\\recip{2}{8}$ が必要になるが、これは存在しない。
///
/// 一般のケースで必要になる場合は、線形篩を用いる方法がある。See:
/// [`LinearSieve::recips`](../struct.LinearSieve.html#method.recips)
///
/// # Complexity
/// $O(n)$ time。
///
/// # Examples
/// ```
/// use nekolib::math::mod_recip_table_prime;
///
/// assert_eq!(mod_recip_table_prime(2, 3), [0, 1, 2]);
/// assert_eq!(mod_recip_table_prime(4, 5), [0, 1, 3, 2, 4]);
/// assert_eq!(mod_recip_table_prime(9, 5), [0, 1, 3, 2, 4].repeat(2));
/// ```
pub fn mod_recip_table_prime(n: u64, m: u64) -> Vec<u64> {
let mut dp = vec![0; n as usize + 1];
if 1 <= n {
dp[1] = 1;
}
for i in 2..=n.min(m - 1) {
let (q, r) = (m / i, m % i);
if dp[r as usize] > 0 {
dp[i as usize] = m - q * dp[r as usize] % m;
}
}
for i in m..=n {
dp[i as usize] = dp[(i - m) as usize];
}
dp
}
#[test]
fn test() {
use factors_dup::FactorsDup;
use gcd::Gcd;
for m in (2_u64..=1000).filter(|m| m.factors_dup().count() == 1) {
let n = m - 1;
let actual = mod_recip_table_prime(n, m);
for i in 0..=n {
let recip = actual[i as usize];
if recip == 0 {
assert_ne!(i.gcd(m), 1);
} else {
assert!(recip < m);
assert_eq!(i * recip % m, 1);
}
}
}
}