generated from mschoi/template
Add new problem modules prob800 and prob853, and update dependencies
- Introduced the `prob800` module, implementing a function to count hybrid integers with corresponding unit tests. - Added the `prob853` module, which includes functions for calculating Pisano periods and their factors, along with extensive unit tests. - Updated `mod.rs` to include the new problem modules. - Added the `indicatif` dependency to `Cargo.toml` for progress indication in long-running tasks. - Enhanced the `factor` utility with a new function to derive divisors from prime factorization.
This commit is contained in:
@@ -8,6 +8,7 @@ approx = "0.5.1"
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
encoding = "0.2.33"
|
||||
flate2 = "1.1.1"
|
||||
indicatif = "0.18.0"
|
||||
itertools = "0.14.0"
|
||||
ndarray = { version = "0.16.1", features = ["approx"] }
|
||||
num = "0.4.3"
|
||||
|
||||
@@ -11,12 +11,16 @@ pub mod prob686;
|
||||
pub mod prob700;
|
||||
pub mod prob719;
|
||||
pub mod prob751;
|
||||
pub mod prob800;
|
||||
pub mod prob808;
|
||||
pub mod prob816;
|
||||
pub mod prob845;
|
||||
pub mod prob853;
|
||||
pub mod prob869;
|
||||
pub mod prob872;
|
||||
pub mod prob885;
|
||||
pub mod prob926;
|
||||
pub mod prob932;
|
||||
pub mod prob934;
|
||||
pub mod prob938;
|
||||
pub mod prob944;
|
||||
|
||||
43
src/project_euler/prob800.rs
Normal file
43
src/project_euler/prob800.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use crate::utils::prime::prime_iter;
|
||||
|
||||
pub fn count_hybrid_integer(logmax: f64) -> usize {
|
||||
let max_p = logmax.floor() as usize;
|
||||
let primes = prime_iter(max_p)
|
||||
.take_while(|&p| (p as f64).log(2.0) * 2.0 + p as f64 <= logmax)
|
||||
.map(|p| p as f64)
|
||||
.collect::<Vec<f64>>();
|
||||
|
||||
let mut start = 0;
|
||||
let mut pi = primes[start];
|
||||
let mut end = primes.len() - 1;
|
||||
let mut pj = primes[end];
|
||||
|
||||
let mut count = 0;
|
||||
while start < end {
|
||||
if pi * pj.log(2.0) + pj * pi.log(2.0) > logmax {
|
||||
end -= 1;
|
||||
pj = primes[end];
|
||||
continue;
|
||||
}
|
||||
|
||||
count += end - start;
|
||||
start += 1;
|
||||
pi = primes[start];
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_count_hybrid_integer() {
|
||||
assert_eq!(count_hybrid_integer(800f64.log(2.0)), 2);
|
||||
assert_eq!(count_hybrid_integer(800.0 * 800f64.log(2.0)), 10790);
|
||||
assert_eq!(
|
||||
count_hybrid_integer(800800.0 * 800800f64.log(2.0)),
|
||||
1412403576
|
||||
);
|
||||
}
|
||||
}
|
||||
140
src/project_euler/prob853.rs
Normal file
140
src/project_euler/prob853.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
use crate::utils::prime::prime_iter;
|
||||
use num::integer::lcm;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn pisano_period(modulo: u32, expected_period: usize) -> Option<usize> {
|
||||
let (mut prev, mut curr) = (1, 1);
|
||||
|
||||
for idx in 2..=(expected_period + 2) {
|
||||
if curr == 0 && prev == 1 {
|
||||
return Some(idx);
|
||||
}
|
||||
let next = (prev + curr) % modulo;
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn pisano_period_prime_power(prime: u32, k: u32, expected_period: usize) -> bool {
|
||||
let (mut prev, mut curr) = (1, 2);
|
||||
let modulo = prime.pow(k);
|
||||
|
||||
for idx in 3..=(expected_period + 2) {
|
||||
if curr == 0 && prev == 1 {
|
||||
return idx == expected_period;
|
||||
}
|
||||
let next = (prev + curr) % modulo;
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn pisano_period_factors(limit: usize, target_period: usize) -> Vec<usize> {
|
||||
let mut factors = Vec::new();
|
||||
for prime in prime_iter(limit) {
|
||||
if let Some(period) = pisano_period(prime as u32, target_period) {
|
||||
if target_period % period == 0 {
|
||||
factors.push(prime);
|
||||
let mut power = prime;
|
||||
while target_period % power == 0 {
|
||||
factors.push(prime * power);
|
||||
power = power * prime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
factors
|
||||
}
|
||||
|
||||
pub fn sum_pisano_period_is_120() -> u64 {
|
||||
let factors: Vec<(u64, u64)> = vec![
|
||||
(2, 4),
|
||||
(3, 2),
|
||||
(5, 2),
|
||||
(11, 1),
|
||||
(31, 1),
|
||||
(41, 1),
|
||||
(61, 1),
|
||||
(2521, 1),
|
||||
];
|
||||
|
||||
let mut divisor2period = HashMap::from([(1, 1)]);
|
||||
for (prime, power) in factors {
|
||||
let prime_period = pisano_period(prime as u32, 120).unwrap();
|
||||
|
||||
let mut new_divisor2period = HashMap::new();
|
||||
for (divisor, period) in divisor2period {
|
||||
new_divisor2period.insert(divisor, period);
|
||||
for i in 1..=power {
|
||||
let power_period = prime_period * prime.pow(i as u32 - 1) as usize;
|
||||
let new_period = lcm(power_period, period);
|
||||
new_divisor2period.insert(divisor * prime.pow(i as u32), new_period);
|
||||
if 120 % new_period == 0 {
|
||||
new_divisor2period.insert(divisor * prime.pow(i as u32), new_period);
|
||||
}
|
||||
}
|
||||
}
|
||||
divisor2period = new_divisor2period;
|
||||
}
|
||||
|
||||
let mut sum = 0;
|
||||
for (divisor, period) in divisor2period {
|
||||
if period == 120 && divisor < 1_000_000_000 {
|
||||
sum += divisor;
|
||||
}
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_pisano_period() {
|
||||
assert_eq!(pisano_period(2, 30), Some(3));
|
||||
assert_eq!(pisano_period(3, 30), Some(8));
|
||||
assert_eq!(pisano_period(5, 30), Some(20));
|
||||
assert_eq!(pisano_period(7, 30), Some(16));
|
||||
assert_eq!(pisano_period(11, 30), Some(10));
|
||||
assert_eq!(pisano_period(13, 30), Some(28));
|
||||
assert_eq!(pisano_period(17, 50), Some(36));
|
||||
assert_eq!(pisano_period(19, 30), Some(18));
|
||||
assert_eq!(pisano_period(38, 30), Some(18));
|
||||
assert_eq!(pisano_period(76, 30), Some(18));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pisano_period_prime_power() {
|
||||
let primes = [2, 3, 5, 7, 11, 13, 17];
|
||||
for prime in primes {
|
||||
let period = pisano_period(prime, 50).unwrap();
|
||||
for k in 2..=5 {
|
||||
assert!(pisano_period_prime_power(
|
||||
prime,
|
||||
k,
|
||||
period * prime.pow(k - 1) as usize
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pisano_period_factors() {
|
||||
assert_eq!(pisano_period_factors(100, 6), vec![2, 4]);
|
||||
assert_eq!(pisano_period_factors(100, 16), vec![3, 7]);
|
||||
assert_eq!(
|
||||
pisano_period_factors(30_000, 120),
|
||||
vec![2, 4, 8, 16, 3, 9, 5, 25, 11, 31, 41, 61, 2521]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_pisano_period_is_120() {
|
||||
assert_eq!(sum_pisano_period_is_120(), 44511058204);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,22 @@ pub fn factorize(n: usize) -> HashMap<usize, usize> {
|
||||
prime_factors
|
||||
}
|
||||
|
||||
pub fn get_divisors_from_factors(factors: HashMap<usize, usize>) -> HashSet<usize> {
|
||||
let mut divisors = HashSet::from([1]);
|
||||
for (prime, count) in factors {
|
||||
let mut new_divisors = HashSet::new();
|
||||
let mut pp = 1;
|
||||
for _ in 0..=count {
|
||||
for divisor in divisors.clone() {
|
||||
new_divisors.insert(divisor * pp);
|
||||
}
|
||||
pp = pp * prime;
|
||||
}
|
||||
divisors = new_divisors;
|
||||
}
|
||||
divisors
|
||||
}
|
||||
|
||||
pub fn get_divisors(n: usize) -> HashSet<usize> {
|
||||
let prime_factors = factorize(n);
|
||||
let mut divisors = HashSet::from([1]);
|
||||
|
||||
@@ -66,7 +66,7 @@ impl Iterator for PrimeSieve {
|
||||
}
|
||||
|
||||
let prime = self.cursor;
|
||||
if prime % 2 == 1 {
|
||||
if prime % 2 == 1 && prime * prime <= self.max {
|
||||
let end = (self.max / prime) * prime;
|
||||
let mut idx = prime * prime;
|
||||
while idx <= end {
|
||||
|
||||
Reference in New Issue
Block a user