#include using namespace std; #include #include #include #include #include #include #include #include #if defined(__unix__) || defined(__APPLE__) #include #endif template std::istream& operator>>(std::istream& is, std::vector& v); template std::istream& operator>>(std::istream& is, std::pair& p); template std::istream& operator>>(std::istream& is, std::tuple& t); namespace input_detail { #ifdef LOCAL inline std::size_t& read_count() { static std::size_t count = 0; return count; } inline bool& failed_read() { static bool failed = false; return failed; } inline bool stdin_is_terminal() { #if defined(__unix__) || defined(__APPLE__) return isatty(fileno(stdin)); #else return false; #endif } struct EndOfInputChecker { ~EndOfInputChecker() { if (stdin_is_terminal() || failed_read() || std::cin.bad()) return; std::cin >> std::ws; std::string token; if (std::cin >> token) { std::cerr << "[input error] 入力が余っています。\n" << " 最初に余った値: " << token << '\n' << " N と M、H と W、辺数 m、配列長 n などを間違えていないか確認してください。\n"; std::abort(); } } }; inline void ensure_end_checker() { static EndOfInputChecker checker; (void)checker; } inline void begin_input() { ensure_end_checker(); } template void read_one(std::istream& is, T& value) { if (&is != &std::cin) { is >> value; return; } ensure_end_checker(); ++read_count(); if (!(is >> value)) { failed_read() = true; std::cerr << "[input error] 入力が足りないか、型が合いません。\n" << " " << read_count() << " 個目の値を読み込めませんでした。\n" << " N と M、H と W、辺数 m、配列長 n などを間違えていないか確認してください。\n"; std::abort(); } } #else inline void begin_input() { } template void read_one(std::istream& is, T& value) { is >> value; } #endif template void read_values(Args&... args) { (read_one(std::cin, args), ...); } } struct FastIO { FastIO() { std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); } }; inline FastIO fast_io_init; template std::istream& operator>>(std::istream& is, std::pair& p) { input_detail::read_one(is, p.first); input_detail::read_one(is, p.second); return is; } template void read_tuple_impl(std::istream& is, Tuple& t, std::index_sequence) { (..., input_detail::read_one(is, std::get(t))); } template std::istream& operator>>(std::istream& is, std::tuple& t) { read_tuple_impl(is, t, std::index_sequence_for{}); return is; } template std::istream& operator>>(std::istream& is, std::vector& v) { for (auto& elem : v) { input_detail::read_one(is, elem); } return is; } template struct is_pair : std::false_type {}; template struct is_pair> : std::true_type {}; template struct is_tuple : std::false_type {}; template struct is_tuple> : std::true_type {}; template struct is_vector : std::false_type {}; template struct is_vector> : std::true_type {}; template void adjust_zero_indexed(T& val) { using DecayedT = std::decay_t; if constexpr (is_pair::value) { adjust_zero_indexed(val.first); adjust_zero_indexed(val.second); } else if constexpr (is_tuple::value) { std::apply([](auto&... args) { (adjust_zero_indexed(args), ...); }, val); } else if constexpr (is_vector::value) { for (auto& elem : val) { adjust_zero_indexed(elem); } } else if constexpr (std::is_arithmetic_v && !std::is_same_v && !std::is_same_v && !std::is_same_v && !std::is_same_v && #if defined(__cpp_char8_t) !std::is_same_v && #endif !std::is_same_v && !std::is_same_v && !std::is_same_v) { --val; } else { } } using default_type = long; template void read(Args&... args) { input_detail::read_values(args...); } template T read_val() { T val; input_detail::read_one(std::cin, val); return val; } template std::pair read_pair() { std::pair p; input_detail::begin_input(); std::cin >> p; return p; } template std::tuple read_tuple() { std::tuple t; input_detail::begin_input(); std::cin >> t; return t; } template && !std::is_same_v, int> = 0> std::vector read_vec(Size n, bool zero_indexed = false) { std::vector v(n); input_detail::begin_input(); std::cin >> v; if (zero_indexed) { adjust_zero_indexed(v); } return v; } template std::vector read_vec(bool zero_indexed = false) { int n; input_detail::read_one(std::cin, n); return read_vec(n, zero_indexed); } template && !std::is_same_v, int> = 0> std::vector> read_vec_pair(Size n, bool zero_indexed = false) { return read_vec>(n, zero_indexed); } template std::vector> read_vec_pair(bool zero_indexed = false) { int n; input_detail::read_one(std::cin, n); return read_vec_pair(n, zero_indexed); } template && !std::is_same_v, int> = 0> std::vector> read_vec_tuple(Size n, bool zero_indexed = false) { return read_vec>(n, zero_indexed); } template std::vector> read_vec_tuple(bool zero_indexed = false) { int n; input_detail::read_one(std::cin, n); return read_vec_tuple(n, zero_indexed); } template std::vector> read_vec_grid(int h, int w, bool zero_indexed = false) { std::vector> grid(h, std::vector(w)); input_detail::begin_input(); std::cin >> grid; if (zero_indexed) { adjust_zero_indexed(grid); } return grid; } template std::vector> read_vec_grid(bool zero_indexed = false) { int h, w; input_detail::read_values(h, w); return read_vec_grid(h, w, zero_indexed); } template && !std::is_same_v, int> = 0> std::vector> read_vec_var(Size n, bool zero_indexed = false) { std::vector> res(n); input_detail::begin_input(); for (int i = 0; i < static_cast(n); ++i) { int m; input_detail::read_one(std::cin, m); res[i] = read_vec(m, zero_indexed); } return res; } template std::vector> read_vec_var(bool zero_indexed = false) { int n; input_detail::read_one(std::cin, n); return read_vec_var(n, zero_indexed); } template T read_zero_idx() { T val; input_detail::read_one(std::cin, val); adjust_zero_indexed(val); return val; } inline std::vector> read_graph(int n, int m, bool directed = false) { std::vector> g(n); input_detail::begin_input(); for (int i = 0; i < m; ++i) { int u = read_zero_idx(); int v = read_zero_idx(); g[u].push_back(v); if (!directed) { g[v].push_back(u); } } return g; } inline std::vector> read_graph(bool directed = false) { int n, m; input_detail::read_values(n, m); return read_graph(n, m, directed); } #include #include #include #include #define ALL(a) (a).begin(), (a).end() using i128 = __int128; template inline bool chmin(T& a, const U& b) { if (a > b) { a = b; return true; } return false; } template inline bool chmax(T& a, const U& b) { if (a < b) { a = b; return true; } return false; } template inline T div_ceil(T a, T b) { if (a > 0) return a / b + (a % b != 0); return a / b; } template inline T div_floor(T a, T b) { if (a < 0) return a / b - (a % b != 0); return a / b; } template inline T mod(T a, T m) { a %= m; if (a < 0) a += m; return a; } template inline constexpr T INF = std::numeric_limits::max() / 2; template <> inline constexpr float INF = std::numeric_limits::infinity(); template <> inline constexpr double INF = std::numeric_limits::infinity(); template <> inline constexpr long double INF = std::numeric_limits::infinity(); template auto make_vector(size_t size, T&& initial_value) { return std::vector>(size, std::forward(initial_value)); } template auto make_vector(size_t size, Args&&... args) { auto inner = make_vector(std::forward(args)...); return std::vector(size, inner); } template inline std::vector iota_vec(int n, T start = 0) { std::vector v(n); std::iota(v.begin(), v.end(), start); return v; } template inline std::vector doubled_vec(const std::vector& v) { std::vector res; res.reserve(v.size() * 2); res.insert(res.end(), v.begin(), v.end()); res.insert(res.end(), v.begin(), v.end()); return res; } inline void Yes(bool b = true) { std::println("{}", (b ? "Yes" : "No")); } inline void No() { std::println("No"); } #ifdef LOCAL #include #else #define debug(...) #endif #include #include #include #include #include #include #include #include #include #include namespace internal { inline long long mod_mul(long long a, long long b, long long mod) { return (__int128)a * b % mod; } inline long long mod_pow(long long base, long long exp, long long mod) { long long result = 1; base %= mod; while (exp > 0) { if (exp & 1) result = mod_mul(result, base, mod); base = mod_mul(base, base, mod); exp >>= 1; } return result; } inline long long ceil_div(long long x, long long y) { long long q = x / y; long long r = x % y; if (r > 0) ++q; return q; } inline long long isqrt_floor(long long x) { if (x <= 0) return 0; long long r = static_cast(std::sqrt(static_cast(x))); while ((r + 1) <= x / (r + 1)) ++r; while (r > x / r) --r; return r; } } inline bool is_prime_mr(long long n) { if (n < 2) return false; if (n == 2 || n == 3) return true; if (n % 2 == 0) return false; long long d = n - 1; int r = 0; while (d % 2 == 0) { d /= 2; r++; } static constexpr std::array witnesses = {2, 325, 9375, 28178, 450775, 9780504, 1795265022}; for (long long a : witnesses) { long long a_mod = a % n; if (a_mod == 0) continue; long long x = internal::mod_pow(a_mod, d, n); if (x == 1 || x == n - 1) continue; bool composite = true; for (int i = 0; i < r - 1; i++) { x = (__int128)x * x % n; if (x == n - 1) { composite = false; break; } } if (composite) return false; } return true; } inline std::vector> factorize(long long n) { std::vector> result; if (n <= 1) return result; for (long long p = 2; p <= n / p; p++) { if (n % p == 0) { long long cnt = 0; while (n % p == 0) { n /= p; cnt++; } result.emplace_back(p, cnt); } } if (n > 1) result.emplace_back(n, 1); return result; } namespace internal { inline long long pollard_rho(long long n) { if (n % 2 == 0) return 2; if (is_prime_mr(n)) return n; static std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count()); while (true) { long long c = rng() % (n - 1) + 1; auto f = [&](long long x) { return (mod_mul(x, x, n) + c) % n; }; long long x = rng() % (n - 2) + 2; long long y = x; long long g = 1; while (g == 1) { long long ys = y; long long q = 1; constexpr int batch = 128; for (int r = 1; g == 1; r <<= 1) { x = y; for (int i = 0; i < r; i++) y = f(y); for (int k = 0; g == 1 && k < r; k += batch) { ys = y; int bound = std::min(batch, r - k); for (int i = 0; i < bound; i++) { y = f(y); q = mod_mul(q, std::abs(x - y), n); } g = std::gcd(q, n); } } if (g == n) { g = 1; while (g == 1) { ys = f(ys); g = std::gcd(std::abs(x - ys), n); } } } if (g != n) return g; } } inline void collect_factors(long long n, std::vector& result) { if (n <= 1) return; if (is_prime_mr(n)) { result.push_back(n); return; } long long d = pollard_rho(n); collect_factors(d, result); collect_factors(n / d, result); } } inline std::vector> factorize_fast(long long n) { std::vector primes; internal::collect_factors(n, primes); std::sort(primes.begin(), primes.end()); std::vector> result; for (long long p : primes) { if (!result.empty() && result.back().first == p) { result.back().second++; } else { result.emplace_back(p, 1); } } return result; } inline std::vector divisors(long long n) { if (n <= 0) return {}; std::vector result = {1}; for (auto [p, e] : factorize_fast(n)) { int sz = static_cast(result.size()); long long pw = 1; for (long long i = 0; i < e; i++) { pw *= p; for (int j = 0; j < sz; j++) { result.push_back(result[j] * pw); } } } std::sort(result.begin(), result.end()); return result; } inline long long divisor_count(long long n) { if (n <= 0) return 0; long long ans = 1; for (auto [p, e] : factorize_fast(n)) { ans *= (e + 1); } return ans; } inline long long divisor_sum(long long n) { if (n <= 0) return 0; long long ans = 1; for (auto [p, e] : factorize_fast(n)) { long long term = 1; long long cur = 1; for (long long i = 0; i < e; i++) { cur *= p; term += cur; } ans *= term; } return ans; } inline long long divisor_sum_mod(long long n, long long mod) { if (n <= 0 || mod <= 0) return 0; long long ans = 1 % mod; for (auto [p, e] : factorize_fast(n)) { long long term = 1 % mod; long long cur = 1 % mod; long long p_mod = p % mod; for (long long i = 0; i < e; i++) { cur = static_cast((__int128)cur * p_mod % mod); term = (term + cur) % mod; } ans = static_cast((__int128)ans * term % mod); } return ans; } struct Eratosthenes { std::vector is_prime_table; std::vector prime_list; std::vector min_factor; explicit Eratosthenes(int n) { if (n < 0) n = 0; is_prime_table.assign(n + 1, true); min_factor.assign(n + 1, 0); is_prime_table[0] = false; if (n >= 1) { is_prime_table[1] = false; min_factor[1] = 1; } for (int i = 2; i <= n; i++) { if (is_prime_table[i]) { prime_list.push_back(i); min_factor[i] = i; for (long long j = (long long)i * i; j <= n; j += i) { is_prime_table[j] = false; if (min_factor[j] == 0) min_factor[j] = i; } } } } bool is_prime(int n) const { return 0 <= n && n < static_cast(is_prime_table.size()) && is_prime_table[n]; } const std::vector& primes() const { return prime_list; } std::vector> factorize(int n) const { if (n <= 1 || n >= static_cast(min_factor.size())) return {}; std::vector> result; while (n > 1) { int p = min_factor[n]; long long cnt = 0; while (min_factor[n] == p) { n /= p; cnt++; } result.emplace_back(p, cnt); } return result; } std::vector divisors(int n) const { if (n <= 0 || n >= static_cast(min_factor.size())) return {}; std::vector result = {1}; for (auto [p, e] : factorize(n)) { int sz = static_cast(result.size()); long long pw = 1; for (long long i = 0; i < e; i++) { pw *= p; for (int j = 0; j < sz; j++) { result.push_back(result[j] * pw); } } } return result; } long long divisor_count(int n) const { if (n <= 0 || n >= static_cast(min_factor.size())) return 0; long long ans = 1; for (auto [p, e] : factorize(n)) { ans *= (e + 1); } return ans; } long long divisor_sum(int n) const { if (n <= 0 || n >= static_cast(min_factor.size())) return 0; long long ans = 1; for (auto [p, e] : factorize(n)) { long long term = 1; long long cur = 1; for (long long i = 0; i < e; i++) { cur *= p; term += cur; } ans *= term; } return ans; } }; struct LinearSieve { std::vector primes; std::vector min_factor; std::vector phi; std::vector mobius; explicit LinearSieve(int n) { if (n < 0) n = 0; min_factor.assign(n + 1, 0); phi.assign(n + 1, 0); mobius.assign(n + 1, 0); if (n >= 1) { phi[1] = 1; mobius[1] = 1; } for (int i = 2; i <= n; i++) { if (min_factor[i] == 0) { primes.push_back(i); min_factor[i] = i; phi[i] = i - 1; mobius[i] = -1; } for (long long p : primes) { if (p * i > n) break; int pi = static_cast(p * i); min_factor[pi] = static_cast(p); if (i % p == 0) { phi[pi] = phi[i] * static_cast(p); mobius[pi] = 0; break; } else { phi[pi] = phi[i] * (static_cast(p) - 1); mobius[pi] = -mobius[i]; } } } } bool is_prime(int n) const { return n >= 2 && n < static_cast(min_factor.size()) && min_factor[n] == n; } std::vector> factorize(int n) const { if (n <= 1 || n >= static_cast(min_factor.size())) return {}; std::vector> result; while (n > 1) { int p = min_factor[n]; long long cnt = 0; while (n % p == 0) { n /= p; cnt++; } result.emplace_back(p, cnt); } return result; } }; inline std::vector segment_sieve(long long L, long long R) { if (L < 2) L = 2; if (R < L) return {}; long long sqrtR = internal::isqrt_floor(R); assert(sqrtR <= std::numeric_limits::max() && "segment_sieve: sqrt(R) must fit in int for Eratosthenes."); if (sqrtR > std::numeric_limits::max()) return {}; Eratosthenes sieve(static_cast(sqrtR)); const auto& small_primes = sieve.primes(); std::vector is_prime(R - L + 1, true); for (long long p : small_primes) { long long start = std::max(1LL * p * p, internal::ceil_div(L, p) * 1LL * p); for (long long j = start; j <= R; j += p) { is_prime[j - L] = false; } } std::vector result; for (long long i = L; i <= R; i++) { if (is_prime[i - L]) result.push_back(i); } return result; } inline std::vector segment_sieve_bool(long long L, long long R) { if (R < L) return {}; std::vector result(R - L + 1, true); if (L < 2) { long long last = std::min(R, 1LL); if (last >= L) { std::fill(result.begin(), result.begin() + (last - L + 1), false); } } if (R < 2) return result; long long sqrtR = internal::isqrt_floor(R); assert(sqrtR <= std::numeric_limits::max() && "segment_sieve_bool: sqrt(R) must fit in int for Eratosthenes."); if (sqrtR > std::numeric_limits::max()) return {}; Eratosthenes sieve(static_cast(sqrtR)); const auto& small_primes = sieve.primes(); for (long long p : small_primes) { long long start = std::max(1LL * p * p, internal::ceil_div(L, p) * 1LL * p); for (long long j = start; j <= R; j += p) { result[j - L] = false; } } return result; } inline long long count_primes_range(long long L, long long R) { auto primes = segment_sieve(L, R); return primes.size(); } inline std::vector distinct_prime_factor_count_table(int n) { if (n < 0) return {}; std::vector count(n + 1, 0); for (int i = 2; i <= n; i++) { if (count[i] == 0) { for (int j = i; j <= n; j += i) { count[j]++; } } } return count; } inline std::vector total_prime_factor_count_table(int n) { if (n < 0) return {}; std::vector count(n + 1, 0); std::vector min_factor(n + 1, 0); for (int i = 2; i <= n; i++) { if (min_factor[i] == 0) { for (int j = i; j <= n; j += i) { if (min_factor[j] == 0) min_factor[j] = i; } } count[i] = count[i / min_factor[i]] + 1; } return count; } inline std::vector prime_count_table(int n) { if (n < 0) return {}; std::vector is_prime(n + 1, true); std::vector cnt(n + 1, 0); if (n >= 0) is_prime[0] = false; if (n >= 1) is_prime[1] = false; for (int i = 2; i <= n; i++) { if (is_prime[i]) { for (int j = i * 2; j <= n; j += i) is_prime[j] = false; } cnt[i] = cnt[i - 1] + is_prime[i]; } return cnt; } inline long long euler_phi(long long n) { if (n <= 0) return 0; long long result = n; for (long long p = 2; p <= n / p; p++) { if (n % p == 0) { while (n % p == 0) n /= p; result -= result / p; } } if (n > 1) result -= result / n; return result; } inline std::vector divisor_count_table(int n) { if (n < 0) return {}; std::vector count(n + 1, 0); for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j += i) { count[j]++; } } return count; } inline std::vector divisor_sum_table(int n) { if (n < 0) return {}; std::vector sum(n + 1, 0); for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j += i) { sum[j] += i; } } return sum; } void solve() { ios::sync_with_stdio(false); cin.tie(nullptr); long N, M; read(N, M); LinearSieve sieve(N + N); long ans = 0; for (int i = 1; i <= N; i++) { ans += (sieve.mobius[i] * (N / i) * (M / i)); } println("{}", ans); } int main() { solve(); }