115 lines
2.8 KiB
Rust
115 lines
2.8 KiB
Rust
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::<u64>().expect("Parse error on 0"), x.1.parse::<u64>().expect("Parse error on 1")))
|
|
.collect::<Vec<_>>();
|
|
|
|
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::<u64>();
|
|
|
|
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::<Vec<_>>();
|
|
|
|
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
|
|
})
|
|
}
|
|
|