haar_lib/math/
totient_sum.rs1use crate::math::totient::totient_table;
10use crate::num::ff::*;
11use std::collections::HashMap;
12
13pub fn totient_sum<Modulo: FF>(n: u64, m: Modulo) -> Modulo::Element
15where
16 Modulo::Element: FFElem + Copy,
17{
18 let k = (n as f64).powf(0.66) as u64;
19
20 let mut memo1 = vec![m.from_u64(0); k as usize + 1];
21 let table = totient_table(k as usize);
22 let mut sum = m.from_u64(0);
23 for i in 1..=k as usize {
24 sum += m.from_u64(table[i]);
25 memo1[i] = sum;
26 }
27
28 let mut memo2 = HashMap::new();
29
30 rec(n, &m, &memo1, &mut memo2)
31}
32
33fn rec<Modulo: FF>(
34 x: u64,
35 m: &Modulo,
36 memo1: &[Modulo::Element],
37 memo2: &mut HashMap<u64, Modulo::Element>,
38) -> Modulo::Element
39where
40 Modulo::Element: FFElem + Copy,
41{
42 if let Some(y) = memo1.get(x as usize) {
43 return *y;
44 }
45 if let Some(y) = memo2.get(&x) {
46 return *y;
47 }
48
49 let mut ret = if x % 2 == 0 {
50 m.from_u64(x / 2) * m.from_u64(x + 1)
51 } else {
52 m.from_u64(x) * m.from_u64(x.div_ceil(2))
53 };
54
55 let s = (x as f64).sqrt() as u64;
56
57 for i in 2..=s {
58 if x / i > s {
59 ret -= rec(x / i, m, memo1, memo2);
60 }
61 }
62
63 for i in 1..=s {
64 let t = m.from_u64(x / i - x / (i + 1));
65 ret -= rec(i, m, memo1, memo2) * t;
66 }
67
68 memo2.insert(x, ret);
69 ret
70}