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}