120 lines
2.9 KiB
Rust
120 lines
2.9 KiB
Rust
use std::io::Read;
|
|
use std::iter;
|
|
use std::num::{NonZero, NonZeroU32};
|
|
|
|
fn main() {
|
|
let mut problem = parse_problem();
|
|
|
|
println!("Parsed problem: {:?}", 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);
|
|
|
|
println!("Cleaned problem: {:?}", problem);
|
|
|
|
let count = problem.ranges.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 = lowestOfDegree(digitCountU);
|
|
|
|
return vec![(*lower, lowestOfDegree-1, digitCountL), (lowestOfDegree, *upper, digitCountU)];
|
|
}).flatten().collect::<Vec<_>>();
|
|
|
|
return CleanedProblem{ranges: new_ranges};
|
|
}
|
|
|
|
fn lowestOfDegree(degree : NonZeroU32) -> u64{
|
|
10u64.pow(degree.get() - 1)
|
|
}
|
|
|
|
fn compute_range(lower_bound: u64, upper_bound: u64) -> u64 {
|
|
assert!(lower_bound > 0 && upper_bound > 0);
|
|
assert!(upper_bound > lower_bound);
|
|
assert!(count_digits(upper_bound) == count_digits(lower_bound));
|
|
|
|
let digitCount = count_digits(upper_bound);
|
|
|
|
if digitCount.get() % 2 != 0{
|
|
return 0;
|
|
}
|
|
|
|
|
|
let halfDigitCount = NonZeroU32::new(digitCount.get() / 2).unwrap();
|
|
|
|
|
|
|
|
let mut half = (lower_bound / 10u64.pow(halfDigitCount.get())).min(lower_bound % 10u64.pow(halfDigitCount.get()));
|
|
let mut count = 0;
|
|
|
|
loop{
|
|
let whole = combine_numbers(half, halfDigitCount);
|
|
if whole >= lower_bound && whole <= upper_bound{
|
|
count += whole;
|
|
}else if whole > upper_bound{
|
|
break;
|
|
}
|
|
|
|
half += 1;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
fn count_digits(mut n : u64) -> NonZeroU32{
|
|
assert!(n > 0);
|
|
let mut count = 0u64;
|
|
|
|
while (n != 0){
|
|
n = n / 10;
|
|
count +=1 ;
|
|
}
|
|
|
|
return unsafe{NonZeroU32::new_unchecked(count as u32)};
|
|
}
|
|
|
|
fn combine_numbers(half : u64, degree : NonZeroU32) -> u64 {
|
|
return half + half * 10u64.pow(degree.get() as u32)
|
|
} |