Struct nekolib::math::linear_sieve::LinearSieve
source · pub struct LinearSieve { /* private fields */ }
Expand description
線形篩。
Idea
各整数の最小素因数を求めつつ、素数のリストを作成していく。
の最小素因数を と書く。 なる各素数 に対して、 とわかる。 素因数分解の一意性から、各整数の最小素因数の更新は一回ずつしか行われず、線形時間で構築できる。
また、 が と等しいかで場合分けしながら DP することで、各 が で何回割り切れるかも求められる。 なお、これは DP せず各 に対して愚直に計算しても になることが示せるらしい。
Complexity
演算 | 時間計算量 |
---|---|
new | |
is_prime | |
least_factor | |
factors_dup | delay |
factors | delay |
euler_phi | |
euler_phi_star | |
divisors | |
divisors_count | |
divisors_sum | |
primes | delay |
recips |
の素因数の個数を とすると、以下の式が成り立つらしい。
また、 以下の素数の個数を とすると、以下の式が成り立つ(素数定理)。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert!(!sieve.is_prime(1));
assert!(sieve.is_prime(2));
assert!(sieve.is_prime(23));
assert!(!sieve.is_prime(24));
assert_eq!(sieve.least_factor(1), None);
assert_eq!(sieve.least_factor(3), Some(3));
assert_eq!(sieve.least_factor(24), Some(2));
assert_eq!(sieve.factors_dup(1).next(), None);
assert_eq!(sieve.factors_dup(60).collect::<Vec<_>>(), vec![2, 2, 3, 5]);
assert_eq!(
sieve.primes().take(10).collect::<Vec<_>>(),
vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
);
References
- https://cp-algorithms.com/algebra/prime-sieve-linear.html
- https://twitter.com/hidesugar2/status/1431243186362458114
- 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
Implementations§
source§impl LinearSieve
impl LinearSieve
sourcepub fn is_prime(&self, n: usize) -> bool
pub fn is_prime(&self, n: usize) -> bool
が素数であれば true
を返す。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert!(!sieve.is_prime(1));
assert!(sieve.is_prime(2));
assert!(sieve.is_prime(23));
assert!(!sieve.is_prime(24));
sourcepub fn least_factor(&self, n: usize) -> Option<usize>
pub fn least_factor(&self, n: usize) -> Option<usize>
の最小素因数を返す。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.least_factor(1), None);
assert_eq!(sieve.least_factor(3), Some(3));
assert_eq!(sieve.least_factor(24), Some(2));
sourcepub fn factors_dup(&self, n: usize) -> impl Iterator<Item = usize> + '_
pub fn factors_dup(&self, n: usize) -> impl Iterator<Item = usize> + '_
の素因数を列挙する。重複あり。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.factors_dup(1).next(), None);
assert_eq!(sieve.factors_dup(60).collect::<Vec<_>>(), vec![2, 2, 3, 5]);
sourcepub fn factors(&self, n: usize) -> impl Iterator<Item = (usize, u32)> + '_
pub fn factors(&self, n: usize) -> impl Iterator<Item = (usize, u32)> + '_
を素因数分解する。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.factors(1).next(), None);
assert_eq!(
sieve.factors(60).collect::<Vec<_>>(),
vec![(2, 2), (3, 1), (5, 1)]
);
sourcepub fn euler_phi(&self, n: usize) -> usize
pub fn euler_phi(&self, n: usize) -> usize
を求める。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.euler_phi(1), 1);
assert_eq!(sieve.euler_phi(35), 24);
assert_eq!(sieve.euler_phi(60), 16);
sourcepub fn euler_phi_star(&self, n: usize) -> usize
pub fn euler_phi_star(&self, n: usize) -> usize
を求める。
に を繰り返し適用して にするために必要な最小回数である。 に対して なので、 である。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.euler_phi_star(1), 0);
assert_eq!(sieve.euler_phi_star(35), 5);
assert_eq!(sieve.euler_phi_star(60), 5);
assert_eq!(sieve.euler_phi(35), 24);
assert_eq!(sieve.euler_phi(24), 8);
assert_eq!(sieve.euler_phi(8), 4);
assert_eq!(sieve.euler_phi(4), 2);
assert_eq!(sieve.euler_phi(2), 1);
assert_eq!(sieve.euler_phi(60), 16);
assert_eq!(sieve.euler_phi(16), 8);
sourcepub fn divisors(
&self,
n: usize
) -> impl Iterator<Item = usize> + DoubleEndedIterator
pub fn divisors( &self, n: usize ) -> impl Iterator<Item = usize> + DoubleEndedIterator
の約数を列挙する。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.divisors(1).next(), Some(1));
assert_eq!(sieve.divisors(1).nth(1), None);
assert_eq!(
sieve.divisors(60).collect::<Vec<_>>(),
vec![1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60]
);
sourcepub fn divisors_count(&self, n: usize) -> usize
pub fn divisors_count(&self, n: usize) -> usize
の約数の個数を返す。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.divisors_count(1), 1);
assert_eq!(sieve.divisors_count(60), sieve.divisors(60).count());
sourcepub fn divisors_sum(&self, n: usize) -> usize
pub fn divisors_sum(&self, n: usize) -> usize
の約数の総和を返す。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.divisors_sum(1), 1);
assert_eq!(sieve.divisors_sum(8), 15);
assert_eq!(sieve.divisors_sum(60), 168);
sourcepub fn primes(&self) -> impl Iterator<Item = usize> + DoubleEndedIterator + '_
pub fn primes(&self) -> impl Iterator<Item = usize> + DoubleEndedIterator + '_
素数を列挙する。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(
sieve.primes().take(10).collect::<Vec<_>>(),
vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
);
sourcepub fn recips(&self, n: usize, m: usize) -> Vec<usize>
pub fn recips(&self, n: usize, m: usize) -> Vec<usize>
法 での逆元を返す。
を と書く。 次で定められる を返す。 Note: 。
Idea
に基づく。素数は 個しかないため、互除法で愚直に求めても全体では 時間となる。
See also
https://37zigen.com/linear-sieve/#i-4
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(60);
assert_eq!(sieve.recips(0, 1), [0]);
assert_eq!(sieve.recips(4, 5), [0, 1, 3, 2, 4]);
assert_eq!(sieve.recips(9, 10), [0, 1, 0, 7, 0, 0, 0, 3, 0, 9]);
sourcepub fn dp<T>(
&self,
zero: T,
one: T,
eq: impl Fn(&T, usize) -> T,
gt: impl Fn(&T, usize) -> T
) -> Vec<T>
pub fn dp<T>( &self, zero: T, one: T, eq: impl Fn(&T, usize) -> T, gt: impl Fn(&T, usize) -> T ) -> Vec<T>
最小素因数を用いて DP を行う。
関数 であって、任意の に対して となるものを計算する。ただし とする。
(zero, one, eq, gt)
はそれぞれ である。
Examples
use nekolib::math::LinearSieve;
let sieve = LinearSieve::new(10);
// Moebius mu function
let mu = sieve.dp(0, 1, |&x, _| 0, |&x, _| -x);
assert_eq!(mu, [0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1]);
// Euler phi function
let phi = sieve.dp(0, 1, |&x, p| x * p, |&x, p| x * (p - 1));
assert_eq!(phi, [0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4]);
// the number of distinct prime factors
let omega = sieve.dp(0, 0, |&x, _| x, |&x, _| x + 1);
assert_eq!(omega, [0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 2]);
// the number of prime factors
let cap_omega = sieve.dp(0, 0, |&x, _| x + 1, |&x, _| x + 1);
assert_eq!(cap_omega, [0, 0, 1, 1, 2, 1, 2, 1, 3, 2, 2]);
// sum of divisors
let eq = |&(prod, sum, pow): &_, p| (prod, sum + pow * p, pow * p);
let gt = |&(prod, sum, _): &_, p| (prod * sum, 1 + p, p);
let sigma: Vec<_> = sieve.dp((1, 1, 1), (1, 1, 1), eq, gt)
.into_iter().map(|(prod, sum, _)| prod * sum)
.collect();
assert_eq!(sigma, [1, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18]);
Auto Trait Implementations§
impl RefUnwindSafe for LinearSieve
impl Send for LinearSieve
impl Sync for LinearSieve
impl Unpin for LinearSieve
impl UnwindSafe for LinearSieve
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more