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:
2025-09-21 00:05:04 +09:00
parent 81ca2f078d
commit 4075d2ef69
6 changed files with 205 additions and 1 deletions

View File

@@ -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"

View File

@@ -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;

View 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
);
}
}

View 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);
}
}

View File

@@ -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]);

View File

@@ -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 {