/
p074.rs
124 lines (108 loc) · 2.94 KB
/
p074.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! [Problem 74](https://projecteuler.net/problem=74) solver.
#![warn(
bad_style,
unused,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results
)]
use std::collections::HashMap;
#[derive(Clone)]
enum Length {
Loop(usize),
Chain(usize),
Unknown,
}
fn fact_sum(mut n: u32, fs: &[u32; 10]) -> u32 {
if n == 0 {
return 1;
}
let mut sum = 0;
while n > 0 {
sum += fs[(n % 10) as usize];
n /= 10;
}
sum
}
fn get_chain_len(n: u32, map: &mut [Length], fs: &[u32; 10]) -> usize {
let mut chain_map = HashMap::new();
let mut idx = n;
let mut chain_len = 0;
let mut loop_len = 0;
loop {
match map[idx as usize] {
Length::Loop(c) => {
loop_len += c;
break;
}
Length::Chain(c) => {
chain_len += c;
break;
}
Length::Unknown => match chain_map.get(&idx) {
Some(&chain_idx) => {
loop_len = chain_len - chain_idx;
chain_len = chain_idx;
break;
}
None => {
let _ = chain_map.insert(idx, chain_len);
idx = fact_sum(idx, fs);
chain_len += 1;
}
},
}
}
for (&key, &idx) in &chain_map {
if idx >= chain_len {
map[key as usize] = Length::Loop(loop_len);
} else {
map[key as usize] = Length::Chain(loop_len + chain_len - idx);
}
}
chain_len + loop_len
}
fn solve() -> String {
let limit = 1000000;
let factorial = {
let mut val = [1; 10];
for i in 1..10 {
val[i] = val[i - 1] * (i as u32);
}
val
};
let mut map = vec![Length::Unknown; (factorial[9] * 6 + 1) as usize];
let mut cnt = 0;
for n in 1..(limit + 1) {
let len = get_chain_len(n, &mut map, &factorial);
if len == 60 {
cnt += 1;
}
}
cnt.to_string()
}
common::problem!("402", solve);
#[cfg(test)]
mod tests {
use std::iter;
#[test]
fn len() {
let factorial = {
let mut val = [1; 10];
for i in 1..10 {
val[i] = val[i - 1] * (i as u32);
}
val
};
let mut map = iter::repeat(super::Length::Unknown)
.take((factorial[9] * 6 + 1) as usize)
.collect::<Vec<_>>();
assert_eq!(3, super::get_chain_len(169, &mut map, &factorial));
assert_eq!(2, super::get_chain_len(871, &mut map, &factorial));
assert_eq!(2, super::get_chain_len(872, &mut map, &factorial));
assert_eq!(5, super::get_chain_len(69, &mut map, &factorial));
assert_eq!(4, super::get_chain_len(78, &mut map, &factorial));
assert_eq!(2, super::get_chain_len(540, &mut map, &factorial));
}
}