use proconio::input; const MD: i64 = 998244353; const HALF: i64 = MD / 2 + 1; fn solve(n: usize, m: usize) -> i64 { let mu = mu(n.max(m)); let mut ans = 0; for d in 1..=n.max(m) { let a = (n / d) as i64; let b = (m / d) as i64; let mut x = (MD + mu[d] as i64) * d as i64 % MD * d as i64; x %= MD; x *= a * (a + 1) % MD * HALF % MD; x %= MD; x *= b * (b + 1) % MD * HALF % MD; ans += x; ans %= MD; } ans } fn mu(n: usize) -> Vec { let mut t = vec![1; n + 1]; t[0] = 0; let mut p = vec![true; n + 1]; p[0] = false; p[1] = false; for k in 2..=n { if p[k] { for i in 1.. { let ki = k.saturating_mul(i); if ki > n { break; } p[ki] = false; t[ki] *= -1; let kki = ki.saturating_mul(k); if kki > n { continue; } t[kki] = 0; } } } t } fn main() { input! { n: usize, m: usize, } let ans = solve(n, m); println!("{}", ans); } #[cfg(test)] mod tests { use num::Integer; use crate::{solve, MD}; #[test] fn test() { for n in 1..=3000 { for m in 1..=3000 { let ans = solve(n, m); let ans_naive = { let mut ans = 0; for i in 1..=n { for j in 1..=m { if i.gcd(&j) == 1 { ans += (i * j) as i64; ans %= MD; } } } ans }; if ans != ans_naive { panic!("! {} {} -> {} {}", n, m, ans, ans_naive); } } } } #[test] fn test_sample() { assert_eq!(solve(3, 5), 69); assert_eq!(solve(31, 13), 29391); assert_eq!(solve(10000000, 10000000), 283556728); } #[test] fn test_case() { assert_eq!(solve(21, 2940), 605156436); } }