Skip to main content

nekolib/math/
linear_sieve.rs

1//! 線形篩。
2
3use super::gcd_recip;
4
5use gcd_recip::GcdRecip;
6
7/// 線形篩。
8///
9/// # Idea
10/// 各整数の最小素因数を求めつつ、素数のリストを作成していく。
11///
12/// $\\gdef\\lpf#1{\\operatorname{lpf}(#1)}$
13/// $i$ の最小素因数を $\\mathrm{lpf}(i)$ と書く。$j \\le \\lpf{i}$
14/// なる各素数 $j$ に対して、$\\lpf{i\\times j} = j$ とわかる。
15/// 素因数分解の一意性から、各整数の最小素因数の更新は一回ずつしか行われず、線形時間で構築できる。
16///
17/// また、$\\lpf{i}$ が $\\lpf{i / {\\lpf{i}}}$
18/// と等しいかで場合分けしながら DP することで、各 $i$ が $\\lpf{i}$
19/// で何回割り切れるかも求められる。
20/// なお、これは DP せず各 $i$ に対して愚直に計算しても $O(n)$ になることが示せるらしい。
21///
22/// # Complexity
23/// |演算|時間計算量|
24/// |---|---|
25/// |`new`|$\\Theta(n)$|
26/// |`is_prime`|$\\Theta(1)$|
27/// |`least_factor`|$\\Theta(1)$|
28/// |`factors_dup`|$\\Theta(1)$ delay|
29/// |`factors`|$\\Theta(1)$ delay|
30/// |`euler_phi`|$\\Theta(\\omega(n))$|
31/// |`euler_phi_star`|$O(\\omega(n)\\log(n))$|
32/// |`divisors`|$O(\\sigma(n))$|
33/// |`divisors_count`|$O(\\omega(n))$|
34/// |`divisors_sum`|$O(\\omega(n))$|
35/// |`primes`|$\\Theta(1)$ delay|
36/// |`recips`|$O(n)$|
37///
38/// $n$ の素因数の個数を $\\omega(n)$ とすると、以下の式が成り立つらしい。
39/// $$ \\sum\_{i\\le n} \\omega(i) = n\\ln(\\ln(n)) + O(n). $$
40///
41/// また、$n$ 以下の素数の個数を $\\pi(n)$ とすると、以下の式が成り立つ(素数定理)。
42/// $$ \\pi(n) = \\frac{n}{\\ln(n)} + O{\\left(\\frac{n}{\\ln(n)\^2}\\right)}. $$
43///
44/// # Examples
45/// ```
46/// use nekolib::math::LinearSieve;
47///
48/// let sieve = LinearSieve::new(60);
49/// assert!(!sieve.is_prime(1));
50/// assert!(sieve.is_prime(2));
51/// assert!(sieve.is_prime(23));
52/// assert!(!sieve.is_prime(24));
53///
54/// assert_eq!(sieve.least_factor(1), None);
55/// assert_eq!(sieve.least_factor(3), Some(3));
56/// assert_eq!(sieve.least_factor(24), Some(2));
57///
58/// assert_eq!(sieve.factors_dup(1).next(), None);
59/// assert_eq!(sieve.factors_dup(60).collect::<Vec<_>>(), vec![2, 2, 3, 5]);
60///
61/// assert_eq!(
62///     sieve.primes().take(10).collect::<Vec<_>>(),
63///     vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
64/// );
65/// ```
66///
67/// # References
68/// - <https://cp-algorithms.com/algebra/prime-sieve-linear.html>
69/// - <https://twitter.com/hidesugar2/status/1431243186362458114>
70/// - <https://maspypy.com/%E7%B4%A0%E6%95%B0%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E4%B8%8A%E3%81%8B%E3%82%89%E3%81%AE%E8%A9%95%E4%BE%A1%EF%BC%88%E5%88%9D%E7%AD%89%E7%9A%84%E3%81%AA%E8%A8%BC%E6%98%8E%EF%BC%89>
71pub struct LinearSieve {
72    lpf: Vec<usize>,
73    lpf_e: Vec<(usize, u32)>,
74    pr: Vec<usize>,
75}
76
77impl LinearSieve {
78    /// $n$ 以下の自然数に対する篩を用意する。
79    ///
80    /// # Examples
81    /// ```
82    /// use nekolib::math::LinearSieve;
83    ///
84    /// let sieve = LinearSieve::new(60);
85    /// ```
86    pub fn new(n: usize) -> Self {
87        let mut lpf = vec![1; n + 1];
88        let mut pr = vec![];
89        for i in 2..=n {
90            if lpf[i] == 1 {
91                lpf[i] = i;
92                pr.push(i);
93            }
94            let lpf_i = lpf[i];
95            for &j in pr.iter().take_while(|&&j| j <= lpf_i && i * j <= n) {
96                lpf[i * j] = j;
97            }
98        }
99        let mut lpf_e = vec![(1, 0); n + 1];
100        for i in 2..=n {
101            let p = lpf[i];
102            let j = i / p;
103            lpf_e[i] = if lpf[j] == p {
104                (lpf_e[j].0 * p, lpf_e[j].1 + 1)
105            } else {
106                (lpf[i], 1)
107            };
108        }
109        Self { lpf, lpf_e, pr }
110    }
111
112    /// $n$ が素数であれば `true` を返す。
113    ///
114    /// # Examples
115    /// ```
116    /// use nekolib::math::LinearSieve;
117    ///
118    /// let sieve = LinearSieve::new(60);
119    /// assert!(!sieve.is_prime(1));
120    /// assert!(sieve.is_prime(2));
121    /// assert!(sieve.is_prime(23));
122    /// assert!(!sieve.is_prime(24));
123    /// ```
124    pub fn is_prime(&self, n: usize) -> bool { n >= 2 && self.lpf[n] == n }
125
126    /// $n$ の最小素因数を返す。
127    ///
128    /// # Examples
129    /// ```
130    /// use nekolib::math::LinearSieve;
131    ///
132    /// let sieve = LinearSieve::new(60);
133    /// assert_eq!(sieve.least_factor(1), None);
134    /// assert_eq!(sieve.least_factor(3), Some(3));
135    /// assert_eq!(sieve.least_factor(24), Some(2));
136    /// ```
137    pub fn least_factor(&self, n: usize) -> Option<usize> {
138        if n < 2 { None } else { Some(self.lpf[n]) }
139    }
140
141    /// $n$ の素因数を列挙する。重複あり。
142    ///
143    /// # Examples
144    /// ```
145    /// use nekolib::math::LinearSieve;
146    ///
147    /// let sieve = LinearSieve::new(60);
148    /// assert_eq!(sieve.factors_dup(1).next(), None);
149    /// assert_eq!(sieve.factors_dup(60).collect::<Vec<_>>(), vec![2, 2, 3, 5]);
150    /// ```
151    pub fn factors_dup(&self, n: usize) -> impl Iterator<Item = usize> + '_ {
152        std::iter::successors(Some(n), move |&n| Some(n / self.lpf[n]))
153            .take_while(|&n| n > 1)
154            .map(move |n| self.lpf[n])
155    }
156
157    /// $n$ を素因数分解する。
158    ///
159    /// # Examples
160    /// ```
161    /// use nekolib::math::LinearSieve;
162    ///
163    /// let sieve = LinearSieve::new(60);
164    /// assert_eq!(sieve.factors(1).next(), None);
165    /// assert_eq!(
166    ///     sieve.factors(60).collect::<Vec<_>>(),
167    ///     vec![(2, 2), (3, 1), (5, 1)]
168    /// );
169    /// ```
170    pub fn factors(&self, n: usize) -> impl Iterator<Item = (usize, u32)> + '_ {
171        std::iter::successors(Some(n), move |&n| Some(n / self.lpf_e[n].0))
172            .take_while(|&n| n > 1)
173            .map(move |n| (self.lpf[n], self.lpf_e[n].1))
174    }
175
176    /// $\\phi(n)$ を求める。
177    ///
178    /// # Examples
179    /// ```
180    /// use nekolib::math::LinearSieve;
181    ///
182    /// let sieve = LinearSieve::new(60);
183    /// assert_eq!(sieve.euler_phi(1), 1);
184    /// assert_eq!(sieve.euler_phi(35), 24);
185    /// assert_eq!(sieve.euler_phi(60), 16);
186    /// ```
187    pub fn euler_phi(&self, n: usize) -> usize {
188        std::iter::successors(Some(n), move |&n| Some(n / self.lpf_e[n].0))
189            .take_while(|&n| n > 1)
190            .map(|n| self.lpf_e[n].0 / self.lpf[n] * (self.lpf[n] - 1))
191            .product()
192    }
193
194    /// $\\phi^\\star(n)$ を求める。
195    ///
196    /// $n$ に $\\phi$ を繰り返し適用して $1$ にするために必要な最小回数である。
197    /// $n\\gt 1$ に対して $\\phi(\\phi(n)) \\le n/2$ なので、
198    /// $\\phi^\\star(n) = O(\\log(n))$ である。
199    ///
200    /// # Examples
201    /// ```
202    /// use nekolib::math::LinearSieve;
203    ///
204    /// let sieve = LinearSieve::new(60);
205    /// assert_eq!(sieve.euler_phi_star(1), 0);
206    /// assert_eq!(sieve.euler_phi_star(35), 5);
207    /// assert_eq!(sieve.euler_phi_star(60), 5);
208    ///
209    /// assert_eq!(sieve.euler_phi(35), 24);
210    /// assert_eq!(sieve.euler_phi(24), 8);
211    /// assert_eq!(sieve.euler_phi(8), 4);
212    /// assert_eq!(sieve.euler_phi(4), 2);
213    /// assert_eq!(sieve.euler_phi(2), 1);
214    ///
215    /// assert_eq!(sieve.euler_phi(60), 16);
216    /// assert_eq!(sieve.euler_phi(16), 8);
217    /// ```
218    pub fn euler_phi_star(&self, n: usize) -> usize {
219        match n {
220            0..=2 => n / 2,
221            _ => 1 + self.euler_phi_star(self.euler_phi(n)),
222        }
223    }
224
225    /// $n$ の約数を列挙する。
226    ///
227    /// # Examples
228    /// ```
229    /// use nekolib::math::LinearSieve;
230    ///
231    /// let sieve = LinearSieve::new(60);
232    /// assert_eq!(sieve.divisors(1).next(), Some(1));
233    /// assert_eq!(sieve.divisors(1).nth(1), None);
234    /// assert_eq!(
235    ///     sieve.divisors(60).collect::<Vec<_>>(),
236    ///     vec![1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60]
237    /// );
238    /// ```
239    pub fn divisors(
240        &self,
241        n: usize,
242    ) -> impl Iterator<Item = usize> + DoubleEndedIterator {
243        let mut res = vec![1];
244        for (p, e) in self.factors(n) {
245            let mut tmp = vec![];
246            let mut pp = 1;
247            for _ in 1..=e {
248                pp *= p;
249                tmp.extend(res.iter().map(|&x| x * pp));
250            }
251            res.extend(tmp);
252        }
253        res.sort_unstable();
254        res.into_iter()
255    }
256
257    /// $n$ の約数の個数を返す。
258    ///
259    /// # Examples
260    /// ```
261    /// use nekolib::math::LinearSieve;
262    ///
263    /// let sieve = LinearSieve::new(60);
264    /// assert_eq!(sieve.divisors_count(1), 1);
265    /// assert_eq!(sieve.divisors_count(60), sieve.divisors(60).count());
266    /// ```
267    pub fn divisors_count(&self, n: usize) -> usize {
268        self.factors(n).map(|(_, e)| e as usize + 1).product()
269    }
270
271    /// $n$ の約数の総和を返す。
272    ///
273    /// # Examples
274    /// ```
275    /// use nekolib::math::LinearSieve;
276    ///
277    /// let sieve = LinearSieve::new(60);
278    /// assert_eq!(sieve.divisors_sum(1), 1);
279    /// assert_eq!(sieve.divisors_sum(8), 15);
280    /// assert_eq!(sieve.divisors_sum(60), 168);
281    /// ```
282    pub fn divisors_sum(&self, n: usize) -> usize {
283        std::iter::successors(Some(n), move |&n| Some(n / self.lpf_e[n].0))
284            .take_while(|&n| n > 1)
285            .map(|n| (self.lpf_e[n].0 * self.lpf[n] - 1) / (self.lpf[n] - 1))
286            .product()
287    }
288
289    /// 素数を列挙する。
290    ///
291    /// # Examples
292    /// ```
293    /// use nekolib::math::LinearSieve;
294    ///
295    /// let sieve = LinearSieve::new(60);
296    /// assert_eq!(
297    ///     sieve.primes().take(10).collect::<Vec<_>>(),
298    ///     vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
299    /// );
300    /// ```
301    pub fn primes(
302        &self,
303    ) -> impl Iterator<Item = usize> + DoubleEndedIterator + '_ {
304        self.pr.iter().copied()
305    }
306
307    /// 法 $m$ での逆元を返す。
308    ///
309    /// $\\gdef\\recip#1#2{#1^{-1}\_{(#2)}}$
310    /// $i^{-1}\\bmod j$ を $\\recip{i}{j}$ と書く。
311    /// 次で定められる $a = (a\_0, a\_1, \\dots, a\_n)$ を返す。
312    /// $$
313    /// a\_i = \\begin{cases}
314    /// \\recip{i}{m}, & \\text{if }\\recip{i}{m}\\text{ exists}; \\\\
315    /// 0, & \\text{otherwise}.
316    /// \\end{cases}
317    /// $$
318    /// Note: $\\recip{i}{m}\\ne 0$。
319    ///
320    /// # Idea
321    ///
322    /// $$
323    /// \\recip{i}{m} \\equiv \\recip{\\lpf{i}}{m}\\cdot\\recip{(i/{\\lpf{i}})}{m}\\pmod{m}
324    /// $$
325    /// に基づく。素数は $O(n/\\log(n))$ 個しかないため、互除法で愚直に求めても全体では
326    /// $O(n)$ 時間となる。
327    ///
328    /// # See also
329    /// <https://37zigen.com/linear-sieve/#i-4>
330    ///
331    /// # Examples
332    /// ```
333    /// use nekolib::math::LinearSieve;
334    ///
335    /// let sieve = LinearSieve::new(60);
336    /// assert_eq!(sieve.recips(0, 1), [0]);
337    /// assert_eq!(sieve.recips(4, 5), [0, 1, 3, 2, 4]);
338    /// assert_eq!(sieve.recips(9, 10), [0, 1, 0, 7, 0, 0, 0, 3, 0, 9]);
339    /// ```
340    pub fn recips(&self, n: usize, m: usize) -> Vec<usize> {
341        assert!(m > 0);
342        if n == 0 {
343            return vec![0];
344        }
345
346        let mut dp = vec![0; n + 1];
347        dp[1] = 1;
348        for i in 2..=n {
349            let lpf_i = self.lpf[i];
350            if lpf_i == i {
351                if let (1, r) = i.gcd_recip(m) {
352                    dp[i] = r;
353                }
354            } else {
355                dp[i] = dp[lpf_i] * dp[i / lpf_i] % m;
356            }
357        }
358        dp
359    }
360
361    /// 最小素因数を用いて DP を行う。
362    ///
363    /// 関数 $f$ であって、任意の $i\\gt 1$ に対して
364    /// $$
365    /// f(i) = \\begin{cases}
366    /// g\_{=}(f(i/j), \\lpf{i}), & \\text{if }\\lpf{i} = \\lpf{i/j}; \\\\
367    /// g\_{\\gt}(f(i/j), \\lpf{i}), & \\text{if }\\lpf{i} \\gt \\lpf{i/j} \\\\
368    /// \\end{cases}
369    /// $$
370    /// となるものを計算する。ただし $j = \\lpf{i}$ とする。
371    ///
372    /// `(zero, one, eq, gt)` はそれぞれ $(f(0), f(1), g\_{=}, g\_{\\gt})$ である。
373    ///
374    /// # Examples
375    /// ```
376    /// use nekolib::math::LinearSieve;
377    ///
378    /// let sieve = LinearSieve::new(10);
379    ///
380    /// // Moebius mu function
381    /// let mu = sieve.dp(0, 1, |&x, _| 0, |&x, _| -x);
382    /// assert_eq!(mu, [0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1]);
383    ///
384    /// // Euler phi function
385    /// let phi = sieve.dp(0, 1, |&x, p| x * p, |&x, p| x * (p - 1));
386    /// assert_eq!(phi, [0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4]);
387    ///
388    /// // the number of distinct prime factors
389    /// let omega = sieve.dp(0, 0, |&x, _| x, |&x, _| x + 1);
390    /// assert_eq!(omega, [0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2]);
391    ///
392    /// // the number of prime factors
393    /// let cap_omega = sieve.dp(0, 0, |&x, _| x + 1, |&x, _| x + 1);
394    /// assert_eq!(cap_omega, [0, 0, 1, 1, 2, 1, 2, 1, 3, 2, 2]);
395    ///
396    /// // sum of divisors
397    /// let eq = |&(prod, sum, pow): &_, p| (prod, sum + pow * p, pow * p);
398    /// let gt = |&(prod, sum, _): &_, p| (prod * sum, 1 + p, p);
399    /// let sigma: Vec<_> = sieve.dp((1, 1, 1), (1, 1, 1), eq, gt)
400    ///     .into_iter().map(|(prod, sum, _)| prod * sum)
401    ///     .collect();
402    /// assert_eq!(sigma, [1, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18]);
403    /// ```
404    pub fn dp<T>(
405        &self,
406        zero: T,
407        one: T,
408        eq: impl Fn(&T, usize) -> T,
409        gt: impl Fn(&T, usize) -> T,
410    ) -> Vec<T> {
411        let n = self.lpf.len() - 1;
412
413        if n == 0 {
414            return vec![zero];
415        } else if n == 1 {
416            return vec![zero, one];
417        }
418
419        let mut res = vec![zero, one];
420        res.reserve(n + 1);
421        for i in 2..=n {
422            let lpf = self.lpf[i];
423            let tmp = if lpf == self.lpf[i / lpf] {
424                eq(&res[i / lpf], lpf)
425            } else {
426                gt(&res[i / lpf], lpf)
427            };
428            res.push(tmp);
429        }
430        res
431    }
432}
433
434#[test]
435fn test_recips() {
436    let m_max = 2000;
437    let ls = LinearSieve::new(m_max);
438    for m in 2..=m_max {
439        let n = m - 1;
440        let actual = ls.recips(m_max, m);
441        for i in 0..=n {
442            let recip = actual[i];
443            if recip == 0 {
444                assert_ne!(i.gcd_recip(m).0, 1);
445            } else {
446                assert!(recip < m);
447                assert_eq!(i * recip % m, 1);
448            }
449        }
450    }
451}