AGC038 C - LCMs

問題

atcoder.jp

解法

mobile.twitter.com

自分の学習のために式を書き直してみたが全く同じになってしまった……


\begin{eqnarray}
 \sum_{i,j} LCM(A_i, A_j) & = &  \sum_{i,j} \frac{A_i,A_j}{GCD(A_i, A_j)} \\
& = &  \sum_{d} \left(\frac{1}{d} \sum _{i,j, GCD(A_i,A_j)=d}A_i A_j \right)\\
& = &  \sum_{d} \left( f(d) \sum _{i,j,d | GCD(A_i,A_j)}A_i A_j \right) \\
& = &  \sum_{d} \left( f(d)\sum_{d | x} \left(\sum _{i,j, GCD(A_i,A_j)=x}A_i A_j \right) \right) \\
\end{eqnarray}

ここで

\begin{eqnarray}

F(x) &=& \sum _{i,j, GCD(A_i,A_j)=x}A_i A_j
\end{eqnarray}
とすると

\begin{eqnarray}

\sum_{d} (\frac{1}{d} F(d) ) & =& \sum_{d}(f(d)\sum_{d|x} F(x)) \\
& =& \sum_{x}(F(x)\sum_{d|x} f(d)) \\
& =& \sum_{d}(F(d)\sum_{x|d} f(x))

\end{eqnarray}
なので

\begin{eqnarray}
\sum_{x|d} f(x) &=& \frac{1}{d}
\end{eqnarray}

コード

use mod_int::ModInt;

const MOD: usize = 998244353;

fn main() {
    let s = std::io::stdin();
    let mut sc = Scanner { stdin: s.lock() };
    let n: usize = sc.read();
    let a: Vec<usize> = sc.vec(n);
    let max_a = *a.iter().max().unwrap();
    let mut f = vec![ModInt(0); max_a + 1];
    for i in 1..(max_a + 1) {
        f[i] = ModInt(1) / i;
    }
    for x in 1..(max_a + 1) {
        let mut d = x * 2;
        while d <= max_a {
            let fx = f[x];
            f[d] -= fx;
            d += x;
        }
    }

    let mut count = vec![0; max_a + 1];
    for &a in a.iter() {
        count[a] += 1;
    }

    let mut ans = ModInt(0);
    for d in 1..(max_a + 1) {
        let mut x = d;
        let mut sum = ModInt(0);
        let mut sum2 = ModInt(0);
        while x <= max_a {
            // x%d == 0
            // d|x
            sum += ModInt(x) * count[x];
            sum2 += ModInt(x) * x * count[x];
            x += d;
        }
        ans += (sum * sum - sum2) / 2 * f[d];
    }
    println!("{}", ans.0);
}

pub mod mod_int {
    use super::MOD;
    use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};

    type Num = usize;

    #[derive(Clone, Copy)]
    pub struct ModInt<T: Copy + Clone>(pub T);

    impl Add<ModInt<Num>> for ModInt<Num> {
        type Output = ModInt<Num>;
        fn add(self, rhs: ModInt<Num>) -> ModInt<Num> {
            self + rhs.0
        }
    }

    impl Add<Num> for ModInt<Num> {
        type Output = ModInt<Num>;
        fn add(self, rhs: Num) -> ModInt<Num> {
            let mut t = rhs + self.0;
            if t >= MOD {
                t = t - MOD;
            }
            ModInt(t)
        }
    }

    impl Sub<Num> for ModInt<Num> {
        type Output = ModInt<Num>;
        fn sub(self, rhs: Num) -> ModInt<Num> {
            let rhs = if rhs >= MOD { rhs % MOD } else { rhs };
            let value = if self.0 < rhs { self.0 + MOD } else { self.0 };
            ModInt(value - rhs)
        }
    }

    impl Sub<ModInt<Num>> for ModInt<Num> {
        type Output = ModInt<Num>;
        fn sub(self, rhs: ModInt<Num>) -> ModInt<Num> {
            self - rhs.0
        }
    }

    impl AddAssign<Num> for ModInt<Num> {
        fn add_assign(&mut self, other: Num) {
            *self = *self + other;
        }
    }
    impl AddAssign<ModInt<Num>> for ModInt<Num> {
        fn add_assign(&mut self, other: ModInt<Num>) {
            *self = *self + other;
        }
    }

    impl SubAssign<Num> for ModInt<Num> {
        fn sub_assign(&mut self, other: Num) {
            *self = *self - other;
        }
    }

    impl SubAssign<ModInt<Num>> for ModInt<Num> {
        fn sub_assign(&mut self, other: ModInt<Num>) {
            *self = *self - other;
        }
    }

    impl Div<Num> for ModInt<Num> {
        type Output = ModInt<Num>;
        fn div(self, rhs: Num) -> ModInt<Num> {
            self * ModInt(rhs).pow(MOD - 2)
        }
    }

    impl Div<ModInt<Num>> for ModInt<Num> {
        type Output = ModInt<Num>;
        fn div(self, rhs: ModInt<Num>) -> ModInt<Num> {
            self / rhs.0
        }
    }

    impl DivAssign<Num> for ModInt<Num> {
        fn div_assign(&mut self, rhs: Num) {
            *self = *self / rhs
        }
    }
    impl DivAssign<ModInt<Num>> for ModInt<Num> {
        fn div_assign(&mut self, rhs: ModInt<Num>) {
            *self = *self / rhs
        }
    }

    impl Mul<ModInt<Num>> for ModInt<Num> {
        type Output = ModInt<Num>;

        fn mul(self, rhs: ModInt<Num>) -> ModInt<Num> {
            self * rhs.0
        }
    }
    impl Mul<Num> for ModInt<Num> {
        type Output = ModInt<Num>;

        fn mul(self, rhs: Num) -> ModInt<Num> {
            let t = (self.0 * rhs) % MOD;
            ModInt(t)
        }
    }

    impl MulAssign<Num> for ModInt<Num> {
        fn mul_assign(&mut self, rhs: Num) {
            *self = *self * rhs;
        }
    }

    impl MulAssign<ModInt<Num>> for ModInt<Num> {
        fn mul_assign(&mut self, rhs: ModInt<Num>) {
            *self = *self * rhs;
        }
    }

    impl ModInt<Num> {
        pub fn pow(self, e: usize) -> ModInt<Num> {
            let mut result = ModInt(1);
            let mut cur = self;
            let mut e = e;
            while e > 0 {
                if e & 1 == 1 {
                    result *= cur;
                }
                e >>= 1;
                cur *= cur;
            }
            result
        }
    }
}

pub struct Scanner<R> {
    stdin: R,
}

impl<R: std::io::Read> Scanner<R> {
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .stdin
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n')
            .take_while(|&b| b != b' ' && b != b'\n')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}