Problem:
Score : 700 points

Problem Statement

We have an integer sequence of length N: A_0,A_1,\cdots,A_{N-1}.

Find the following sum (\mathrm{lcm}(a, b) denotes the least common multiple of a and b):

\sum_{i=0}^{N-2} \sum_{j=i+1}^{N-1} \mathrm{lcm}(A_i,A_j)

Since the answer may be enormous, compute it modulo 998244353.

Constraints

1 \leq N \leq 200000

1 \leq A_i \leq 1000000

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
A_0\ A_1\ \cdots\ A_{N-1}

Output

Print the sum modulo 998244353.

Sample Input 1

3
2 4 6

Sample Output 1

22

\mathrm{lcm}(2,4)+\mathrm{lcm}(2,6)+\mathrm{lcm}(4,6)=4+6+12=22.

Sample Input 2

8
1 2 3 4 6 8 12 12

Sample Output 2

313

Sample Input 3

10
356822 296174 484500 710640 518322 888250 259161 609120 592348 713644

Sample Output 3

353891724

Solution in Rust (1.42.0) (judge verdict: Accepted)

macro_rules !read_value {($iter :expr ,($($t :tt ) ,*) ) =>{($(read_value !($iter ,$t ) ) ,*) } ;($iter :expr ,[$t :tt ;$len :expr ] ) =>{(0 ..$len ) .map (|_ |read_value !($iter ,$t ) ) .collect ::<Vec <_ >>() } ;($iter :expr ,{$t :tt =>$f :expr } ) =>{$f (read_value !($iter ,$t ) ) } ;($iter :expr ,chars ) =>{read_value !($iter ,String ) .chars () .collect ::<Vec <char >>() } ;($iter :expr ,usize1 ) =>{read_value !($iter ,usize ) -1 } ;($iter :expr ,$t :ty ) =>{$iter .next () .unwrap () .parse ::<$t >() .unwrap () } ;}
macro_rules !input_inner {($iter :expr ) =>{} ;($iter :expr ,) =>{} ;($iter :expr ,mut $var :ident :$t :tt $($r :tt ) *) =>{let mut $var =read_value !($iter ,$t ) ;input_inner !{$iter $($r ) *} } ;($iter :expr ,mut $var :ident $($r :tt ) *) =>{input_inner !{$iter ,mut $var :usize $($r ) *} } ;($iter :expr ,$var :ident :$t :tt $($r :tt ) *) =>{let $var =read_value !($iter ,$t ) ;input_inner !{$iter $($r ) *} } ;($iter :expr ,$var :ident $($r :tt ) *) =>{input_inner !{$iter ,$var :usize $($r ) *} } ;}
macro_rules !input {(source =$s :expr ,$($r :tt ) *) =>{let mut iter =$s .split_whitespace () ;input_inner !{iter ,$($r ) *} } ;(iter =$iter :ident ,$($r :tt ) *) =>{let s ={use std ::io ::Read ;let mut s =String ::new () ;std ::io ::stdin () .read_to_string (&mut s ) .unwrap () ;s } ;let mut $iter =s .split_whitespace () ;input_inner !{$iter ,$($r ) *} } ;($($r :tt ) *) =>{let s ={use std ::io ::Read ;let mut s =String ::new () ;std ::io ::stdin () .read_to_string (&mut s ) .unwrap () ;s } ;let mut iter =s .split_whitespace () ;input_inner !{iter ,$($r ) *} } ;}
/// binary operaion: T ∘ T → T
pub trait Magma {
    /// type of operands: T
    type T: Clone + PartialEq;
    /// binary operaion: ∘
    fn operate(&self, x: &Self::T, y: &Self::T) -> Self::T;
}
/// ∀a,b,c ∈ T, (a ∘ b) ∘ c = a ∘ (b ∘ c)
pub trait Associative {}
/// associative binary operation
pub trait SemiGroup: Magma + Associative {}
impl<S: Magma + Associative> SemiGroup for S {}
/// ∃e ∈ T, ∀a ∈ T, e ∘ a = a ∘ e = e
pub trait Unital: Magma {
    /// identity element: e
    fn unit(&self) -> Self::T;
}
/// associative binary operation and an identity element
pub trait Monoid: SemiGroup + Unital {
    /// x ^ n = x ∘ ... ∘ x
    /// binary exponentiation
    fn pow(&self, x: Self::T, n: usize) -> Self::T {
        let mut n = n;
        let mut res = self.unit();
        let mut base = x;
        while n > 0 {
            if n & 1 == 1 {
                res = self.operate(&res, &base);
            }
            base = self.operate(&base, &base);
            n = n >> 1;
        }
        res
    }
}
impl<M: SemiGroup + Unital> Monoid for M {}
/// ∃e ∈ T, ∀a ∈ T, ∃b,c ∈ T, b ∘ a = a ∘ c = e
pub trait Invertible: Magma {
    /// a where a ∘ x = e
    fn inverse(&self, x: &Self::T) -> Self::T;
}
/// associative binary operation and an identity element and inverse elements
pub trait Group: Monoid + Invertible {}
impl<G: Monoid + Invertible> Group for G {}
/// ∀a,b ∈ T, a ∘ b = b ∘ a
pub trait Commutative {}
/// commutative monoid
pub trait AbelianMonoid: Monoid + Commutative {}
impl<M: Monoid + Commutative> AbelianMonoid for M {}
/// commutative group
pub trait AbelianGroup: Group + Commutative {}
impl<G: Group + Commutative> AbelianGroup for G {}
/// ∀a ∈ T, a ∘ a = a
pub trait Idempotent {}
/// idempotent monoid
pub trait IdempotentMonoid: Monoid + Idempotent {}
impl<M: Monoid + Idempotent> IdempotentMonoid for M {}
/// +
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct AdditiveOperation<T: Copy + PartialEq + AdditiveIdentity> {
    phantom: std::marker::PhantomData<T>,
}
pub trait AdditiveIdentity: Sized + std::ops::Add<Output = Self> {
    fn zero() -> Self;
}
#[macro_use]
pub mod additive_operation_impl {
    use super::*;
    #[macro_export(local_inner_macros)]
    macro_rules !impl_additive_identity {([$($wh :tt ) *] ,$t :ty ,$zero :expr ) =>{impl <$($wh ) *>AdditiveIdentity for $t {#[inline ] fn zero () ->Self {$zero } } } ;($t :ty ,$zero :expr ) =>{impl AdditiveIdentity for $t {#[inline ] fn zero () ->Self {$zero } } } ;}
    impl_additive_identity!(usize, 0usize);
    impl_additive_identity!(u8, 0u8);
    impl_additive_identity!(u16, 0u16);
    impl_additive_identity!(u32, 0u32);
    impl_additive_identity!(u64, 0u64);
    impl_additive_identity!(isize, 0isize);
    impl_additive_identity!(i8, 0i8);
    impl_additive_identity!(i16, 0i16);
    impl_additive_identity!(i32, 0i32);
    impl_additive_identity!(i64, 0i64);
    impl_additive_identity!(f32, 0.0f32);
    impl_additive_identity!(f64, 0.0f64);
    impl<T: Copy + PartialEq + AdditiveIdentity> AdditiveOperation<T> {
        pub fn new() -> Self {
            AdditiveOperation {
                phantom: std::marker::PhantomData,
            }
        }
    }
    impl<T: Copy + PartialEq + AdditiveIdentity> Magma for AdditiveOperation<T> {
        type T = T;
        #[inline]
        fn operate(&self, x: &Self::T, y: &Self::T) -> Self::T {
            *x + *y
        }
    }
    impl<T: Copy + PartialEq + AdditiveIdentity> Unital for AdditiveOperation<T> {
        #[inline]
        fn unit(&self) -> Self::T {
            AdditiveIdentity::zero()
        }
    }
    impl<T: Copy + PartialEq + AdditiveIdentity> Associative for AdditiveOperation<T> {}
    impl<T: Copy + PartialEq + AdditiveIdentity> Commutative for AdditiveOperation<T> {}
    impl<T: Copy + PartialEq + AdditiveIdentity + std::ops::Neg<Output = T>> Invertible
        for AdditiveOperation<T>
    {
        #[inline]
        fn inverse(&self, x: &Self::T) -> Self::T {
            -*x
        }
    }
}
pub trait Modulo: Copy {
    const MODULO: u32;
    #[inline]
    fn modulo(x: u32) -> u32 {
        x % Self::MODULO
    }
}
pub mod modulos {
    use super::*;
    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
    pub struct Modulo1000000007 {}
    impl Modulo for Modulo1000000007 {
        const MODULO: u32 = 1_000_000_007;
    }
    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
    pub struct Modulo1000000009 {}
    impl Modulo for Modulo1000000009 {
        const MODULO: u32 = 1_000_000_009;
    }
    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
    pub struct Modulo998244353 {}
    impl Modulo for Modulo998244353 {
        const MODULO: u32 = 998_244_353;
    }
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Modu32<M = modulos::Modulo1000000007>
where
    M: Modulo,
{
    x: u32,
    phantom: std::marker::PhantomData<M>,
}
impl<M: Modulo> Modu32<M> {
    #[inline]
    pub fn new(x: u32) -> Self {
        Self {
            x: M::modulo(x),
            phantom: std::marker::PhantomData,
        }
    }
    #[inline]
    pub fn new_unchecked(x: u32) -> Self {
        Self {
            x,
            phantom: std::marker::PhantomData,
        }
    }
    #[inline]
    pub fn one() -> Self {
        Self::new_unchecked(1)
    }
    #[inline]
    pub fn zero() -> Self {
        Self::new_unchecked(0)
    }
    #[inline]
    pub fn get_mod() -> u32 {
        M::MODULO
    }
    #[inline]
    pub fn pow(mut self, mut y: usize) -> Self {
        let mut x = Self::one();
        while y > 0 {
            if y & 1 == 1 {
                x *= self;
            }
            self *= self;
            y >>= 1;
        }
        x
    }
    #[inline]
    pub fn inv(self) -> Self {
        let mut a = self.x;
        let (mut b, mut u, mut s) = (M::MODULO, 1, 0);
        let k = a.trailing_zeros();
        a >>= k;
        for _ in 0..k {
            if u & 1 == 1 {
                u += M::MODULO;
            }
            u /= 2;
        }
        while a != b {
            if b < a {
                std::mem::swap(&mut a, &mut b);
                std::mem::swap(&mut u, &mut s);
            }
            b -= a;
            if s < u {
                s += M::MODULO;
            }
            s -= u;
            let k = b.trailing_zeros();
            b >>= k;
            for _ in 0..k {
                if s & 1 == 1 {
                    s += M::MODULO;
                }
                s /= 2;
            }
        }
        Self::new_unchecked(s)
    }
}
pub mod modu32_impl {
    use super::*;
    use std::{
        fmt,
        iter::{Product, Sum},
        num::ParseIntError,
        ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
        str::FromStr,
    };
    impl<M: Modulo> From<u32> for Modu32<M> {
        #[inline]
        fn from(x: u32) -> Self {
            Self::new(x)
        }
    }
    impl<M: Modulo> From<u64> for Modu32<M> {
        #[inline]
        fn from(x: u64) -> Self {
            Self::new_unchecked((x % M::MODULO as u64) as u32)
        }
    }
    impl<M: Modulo> Add for Modu32<M> {
        type Output = Self;
        #[inline]
        fn add(self, rhs: Self) -> Self::Output {
            let mut x = self.x + rhs.x;
            if x >= M::MODULO {
                x -= M::MODULO;
            }
            Self::new_unchecked(x)
        }
    }
    impl<M: Modulo> Sub for Modu32<M> {
        type Output = Self;
        #[inline]
        fn sub(self, rhs: Self) -> Self::Output {
            if self.x < rhs.x {
                Self::new_unchecked(self.x + M::MODULO - rhs.x)
            } else {
                Self::new_unchecked(self.x - rhs.x)
            }
        }
    }
    impl<M: Modulo> Mul for Modu32<M> {
        type Output = Self;
        #[inline]
        fn mul(self, rhs: Self) -> Self::Output {
            Self::new_unchecked((self.x as u64 * rhs.x as u64 % M::MODULO as u64) as u32)
        }
    }
    impl<M: Modulo> Div for Modu32<M> {
        type Output = Self;
        #[inline]
        fn div(self, rhs: Self) -> Self::Output {
            self * rhs.inv()
        }
    }
    impl<M: Modulo> Neg for Modu32<M> {
        type Output = Self;
        #[inline]
        fn neg(self) -> Self::Output {
            if self.x == 0 {
                Self::zero()
            } else {
                Self::new_unchecked(M::MODULO - self.x)
            }
        }
    }
    impl<M: Modulo> Sum for Modu32<M> {
        #[inline]
        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.fold(Self::zero(), Add::add)
        }
    }
    impl<M: Modulo> Product for Modu32<M> {
        #[inline]
        fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.fold(Self::one(), Mul::mul)
        }
    }
    impl<'a, M: Modulo + 'a> Sum<&'a Modu32<M>> for Modu32<M> {
        #[inline]
        fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
            iter.fold(Self::zero(), Add::add)
        }
    }
    impl<'a, M: Modulo + 'a> Product<&'a Modu32<M>> for Modu32<M> {
        #[inline]
        fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
            iter.fold(Self::one(), Mul::mul)
        }
    }
    impl<M: Modulo> fmt::Display for Modu32<M> {
        fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> {
            write!(f, "{}", self.x)
        }
    }
    impl<M: Modulo> FromStr for Modu32<M> {
        type Err = ParseIntError;
        #[inline]
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            s.parse::<u32>().map(Self::new_unchecked)
        }
    }
    macro_rules! modu32_ref_binop {
        ($imp :ident ,$method :ident ,$t :ty ) => {
            impl<M: Modulo> $imp<$t> for &$t {
                type Output = <$t as $imp<$t>>::Output;
                #[inline]
                fn $method(self, other: $t) -> <$t as $imp<$t>>::Output {
                    $imp::$method(*self, other)
                }
            }
            impl<M: Modulo> $imp<&$t> for $t {
                type Output = <$t as $imp<$t>>::Output;
                #[inline]
                fn $method(self, other: &$t) -> <$t as $imp<$t>>::Output {
                    $imp::$method(self, *other)
                }
            }
            impl<M: Modulo> $imp<&$t> for &$t {
                type Output = <$t as $imp<$t>>::Output;
                #[inline]
                fn $method(self, other: &$t) -> <$t as $imp<$t>>::Output {
                    $imp::$method(*self, *other)
                }
            }
        };
    }
    modu32_ref_binop!(Add, add, Modu32<M>);
    modu32_ref_binop!(Sub, sub, Modu32<M>);
    modu32_ref_binop!(Mul, mul, Modu32<M>);
    modu32_ref_binop!(Div, div, Modu32<M>);
    macro_rules! modu32_ref_unop {
        ($imp :ident ,$method :ident ,$t :ty ) => {
            impl<M: Modulo> $imp for &$t {
                type Output = <$t as $imp>::Output;
                #[inline]
                fn $method(self) -> <$t as $imp>::Output {
                    $imp::$method(*self)
                }
            }
        };
    }
    modu32_ref_unop!(Neg, neg, Modu32<M>);
    macro_rules! modu32_ref_op_assign {
        ($imp :ident ,$method :ident ,$t :ty ,$fromimp :ident ,$frommethod :ident ) => {
            impl<M: Modulo> $imp<$t> for $t {
                #[inline]
                fn $method(&mut self, rhs: $t) {
                    *self = $fromimp::$frommethod(*self, rhs);
                }
            }
            impl<M: Modulo> $imp<&$t> for $t {
                #[inline]
                fn $method(&mut self, other: &$t) {
                    $imp::$method(self, *other);
                }
            }
        };
    }
    modu32_ref_op_assign!(AddAssign, add_assign, Modu32<M>, Add, add);
    modu32_ref_op_assign!(SubAssign, sub_assign, Modu32<M>, Sub, sub);
    modu32_ref_op_assign!(MulAssign, mul_assign, Modu32<M>, Mul, mul);
    modu32_ref_op_assign!(DivAssign, div_assign, Modu32<M>, Div, div);
}
impl_additive_identity!([M: Modulo + PartialEq], Modu32<M>, Self::zero());

pub fn zeta_transform_for_divisor<I: Iterator<Item = usize>, M: Monoid>(
    v: &mut [M::T],
    primes: I,
    monoid: M,
) {
    for p in primes {
        for (i, j) in (0..v.len()).step_by(p).enumerate() {
            v[j] = monoid.operate(&v[j], &v[i]);
        }
    }
}
pub fn zeta_transform_for_multiple<I: Iterator<Item = usize>, M: Monoid>(
    v: &mut [M::T],
    primes: I,
    monoid: M,
) {
    for p in primes {
        for (i, j) in (0..v.len()).step_by(p).enumerate().rev() {
            v[i] = monoid.operate(&v[i], &v[j]);
        }
    }
}
pub fn mobius_transform_for_divisor<I: Iterator<Item = usize>, G: Group>(
    v: &mut [G::T],
    primes: I,
    group: G,
) {
    for p in primes {
        for (i, j) in (0..v.len()).step_by(p).enumerate().rev() {
            v[j] = group.operate(&v[j], &group.inverse(&v[i]));
        }
    }
}
pub fn mobius_transform_for_multiple<I: Iterator<Item = usize>, G: Group>(
    v: &mut [G::T],
    primes: I,
    group: G,
) {
    for p in primes {
        for (i, j) in (0..v.len()).step_by(p).enumerate() {
            v[i] = group.operate(&v[i], &group.inverse(&v[j]));
        }
    }
}
pub fn primes(n: usize) -> Vec<usize> {
    if n < 2 {
        return vec![];
    }
    let mut res = vec![2];
    let sqrt_n = (n as f32).sqrt() as usize | 1;
    let mut seive = vec![true; n / 2];
    for i in (3..=sqrt_n).step_by(2) {
        if seive[i / 2 - 1] {
            res.push(i);
            for j in (i * i..=n).step_by(i * 2) {
                seive[j / 2 - 1] = false;
            }
        }
    }
    for i in (std::cmp::max(3, sqrt_n + 2)..=n).step_by(2) {
        if seive[i / 2 - 1] {
            res.push(i);
        }
    }
    res
}
fn main() {
    #[allow(unused_imports)]
    use std::io::Write as _;
    let __out = std::io::stdout();
    #[allow(unused_mut, unused_variables)]
    let mut __out = std::io::BufWriter::new(__out.lock());
    #[allow(unused_macros)]
    macro_rules !print {($($arg :tt ) *) =>(::std ::write !(__out ,$($arg ) *) .unwrap () ) }
    #[allow(unused_macros)]
    macro_rules !println {($($arg :tt ) *) =>(::std ::writeln !(__out ,$($arg ) *) .unwrap () ) }
    #[allow(unused_macros)]
    macro_rules! echo {
        ($iter :expr ) => {
            echo!($iter, "\n")
        };
        ($iter :expr ,$sep :expr ) => {
            let mut iter = $iter;
            if let Some(item) = iter.next() {
                print!("{}", item);
            }
            for item in iter {
                print!("{}{}", $sep, item);
            }
            println!();
        };
    }
    input!(n, a: [usize; n]);

    type M = Modu32<modulos::Modulo998244353>;
    const A_MAX: usize = 1_000_001;
    let p = primes(A_MAX);
    let mut b = vec![M::zero(); A_MAX];
    let mut ans = M::zero();
    for x in a.iter().cloned() {
        let y = M::new(x as u32);
        ans -= y;
        b[x] += y;
    }
    zeta_transform_for_multiple(&mut b, p.iter().cloned(), AdditiveOperation::new());
    for i in 1..A_MAX {
        b[i] = b[i] * b[i];
    }
    mobius_transform_for_multiple(&mut b, p.iter().cloned(), AdditiveOperation::new());
    for i in 1..A_MAX {
        ans += b[i] / M::new(i as u32);
    }
    println!("{}", ans / M::new(2));
}