use std::collections::HashSet; use std::io::Read; use std::iter; use std::num::{NonZero, NonZeroU32, NonZeroU64}; use rayon::prelude::*; fn main() { let mut problem = parse_problem(); println!("Count in total: {}", compute_problem(&mut problem)) } #[derive(Debug)] struct Problem{ ranges: Vec<(u64, u64)> } #[derive(Debug)] struct CleanedProblem{ ranges: Vec<(u64, u64, NonZeroU32)> } fn parse_problem() -> Problem { let mut input = String::new(); std::io::stdin().read_to_string(&mut input).expect("Failed to read input"); let ranges = input.split(','). map(|x| x.split_once('-').expect("dash in there")) .map(|x| (x.0.parse::().expect("Parse error on 0"), x.1.parse::().expect("Parse error on 1"))) .collect::>(); return Problem{ ranges, }; } fn compute_problem(problem: &mut Problem) -> u64 { //Potentialy ensure it is not overlapping let problem = clean_problem(problem); let count = problem.ranges.par_iter().map(|range| compute_range(range.0, range.1)).sum::(); return count; } fn clean_problem(problem: &Problem) -> CleanedProblem { let new_ranges = problem.ranges.iter().map(|(lower, upper)|{ if (upper < lower){ return vec![] } let digitCountU = count_digits(*upper); let digitCountL = count_digits(*lower); if (digitCountL == digitCountU){ return vec![(*lower, *upper, digitCountU)]; } let lowestOfDegree = lowest_of_degree(digitCountU); return vec![(*lower, lowestOfDegree-1, digitCountL), (lowestOfDegree, *upper, digitCountU)]; }).flatten().collect::>(); return CleanedProblem{ranges: new_ranges}; } fn lowest_of_degree(degree : NonZeroU32) -> u64{ 10u64.pow(degree.get() - 1) } fn compute_range(lower_bound: u64, upper_bound: u64) -> u64 { let digitCount = count_digits(lower_bound); (lower_bound..=upper_bound).map(|i|{ if is_combination(i) { Some(i) }else{ None } }).flatten().sum() } fn count_digits(mut n : u64) -> NonZeroU32{ let mut count = 0u64; while (n != 0){ n = n / 10; count +=1 ; } return unsafe{NonZeroU32::new_unchecked(count as u32)}; } fn is_combination(n: u64) -> bool { let digit_count = count_digits(n).get(); (1..=digit_count) .filter(|count| digit_count % count == 0) .filter(|count| *count <= digit_count/ 2) .any(|count| { let mask = 10u64.pow(count as u32); let block = n % mask; let mut x = n; while x > 0 { if x % mask != block { return false; } x /= mask; } true }) }