#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define allof(obj) (obj).begin(), (obj).end() #define range(i, l, r) for(int i=l;i>1)|y_bit)) #define bit_kth(i, k) ((i >> k)&1) #define bit_highest(i) (i?63-__builtin_clzll(i):-1) #define bit_lowest(i) (i?__builtin_ctzll(i):-1) #define sleepms(t) std::this_thread::sleep_for(std::chrono::milliseconds(t)) using ll = long long; using ld = long double; using ul = uint64_t; using pi = std::pair; using pl = std::pair; using namespace std; template std::ostream &operator << (std::ostream &dest, const std::pair &p) { dest << p.first << ' ' << p.second; return dest; } template std::ostream &operator << (std::ostream &dest, const std::tuple &t) { dest << std::get<0>(t) << ' ' << std::get<1>(t); return dest; } template std::ostream &operator << (std::ostream &dest, const std::tuple &t) { dest << std::get<0>(t) << ' ' << std::get<1>(t) << ' ' << std::get<2>(t); return dest; } template std::ostream &operator << (std::ostream &dest, const std::tuple &t) { dest << std::get<0>(t) << ' ' << std::get<1>(t) << ' ' << std::get<2>(t) << ' ' << std::get<3>(t); return dest; } template std::ostream &operator << (std::ostream &dest, const std::vector> &v) { int sz = v.size(); if (!sz) return dest; for (int i = 0; i < sz; i++) { int m = v[i].size(); for (int j = 0; j < m; j++) dest << v[i][j] << (i != sz - 1 && j == m - 1 ? '\n' : ' '); } return dest; } template std::ostream &operator << (std::ostream &dest, const std::vector &v) { int sz = v.size(); if (!sz) return dest; for (int i = 0; i < sz - 1; i++) dest << v[i] << ' '; dest << v[sz - 1]; return dest; } template std::ostream &operator << (std::ostream &dest, const std::array &v) { if (!sz) return dest; for (int i = 0; i < sz - 1; i++) dest << v[i] << ' '; dest << v[sz - 1]; return dest; } template std::ostream &operator << (std::ostream &dest, const std::set &v) { for (auto itr = v.begin(); itr != v.end();) { dest << *itr; itr++; if (itr != v.end()) dest << ' '; } return dest; } template std::ostream &operator << (std::ostream &dest, const std::map &v) { for (auto itr = v.begin(); itr != v.end(); ) { dest << '(' << itr->first << ", " << itr->second << ')'; itr++; if (itr != v.end()) dest << '\n'; } return dest; } template vector make_vec(size_t sz, T val) { return std::vector(sz, val); } template auto make_vec(size_t sz, Tail ...tail) { return std::vector(tail...))>(sz, make_vec(tail...)); } template vector read_vec(size_t sz) { std::vector v(sz); for (int i = 0; i < (int)sz; i++) std::cin >> v[i]; return v; } template auto read_vec(size_t sz, Tail ...tail) { auto v = std::vector(tail...))>(sz); for (int i = 0; i < (int)sz; i++) v[i] = read_vec(tail...); return v; } // x / y以上の最小の整数 ll ceil_div(ll x, ll y) { assert(y > 0); return (x + (x > 0 ? y - 1 : 0)) / y; } // x / y以下の最大の整数 ll floor_div(ll x, ll y) { assert(y > 0); return (x + (x > 0 ? 0 : -y + 1)) / y; } void io_init() { std::cin.tie(nullptr); std::ios::sync_with_stdio(false); } #include uint64_t random64() { static std::random_device seed_gen; static std::mt19937_64 engine(seed_gen()); return engine(); } struct hash_fast { static uint64_t r64; static uint32_t r32; static uint64_t hash_u64(uint64_t x) { x += r64; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return (x ^ (x >> 31)); } static uint32_t hash_u32(uint32_t x) { x += r32; x = (x ^ (x >> 16)) * 0x7feb352d; x = (x ^ (x >> 15)) * 0x846ca68b; return x ^ (x >> 16); } // ペアのハッシュ {x, y}と{y, x}は異なるとする static uint64_t hash_u64_u64(std::pair p) { return hash_u64(hash_u64(p.first) + p.second); } // ペアのハッシュ {x, y}と{y, x}は異なるとする static uint64_t hash_u32_u32(std::pair p) { return hash_u64(((uint64_t)p.first << 32) + p.second); } template static uint64_t hash(T x) { assert(false); } static uint64_t hash(uint64_t x) { return hash_u64(x); } static uint64_t hash(long long x) { return hash_u64(x); } static uint64_t hash(uint32_t x) { return hash_u32(x); } static uint64_t hash(int x) { return hash_u32(x); } static uint64_t hash(std::pair x) { return hash_u64_u64(x); } static uint64_t hash(std::pair x) { return hash_u32_u32(x); } }; uint64_t hash_fast::r64 = random64(); uint32_t hash_fast::r32 = random64(); constexpr unsigned int bit_ceil(unsigned int n) { unsigned int x = 1; while (x < (unsigned int)(n)) x *= 2; return x; } constexpr int bit_ceil_log(unsigned int n) { int x = 0; while ((1 << x) < (unsigned int)(n)) x++; return x; } // 高速化のために以下のような実装 // ・INFとINFを無効な値にする(入れると壊れる) // ・サイズの縮小を行わなないため要素列挙を行えない template struct hash_map { private: static constexpr S _NULL = std::numeric_limits::max(); static constexpr T _ERASED = std::numeric_limits::max(); int _size_mod; // table.size() - 1 int _cnt_data; // データサイズ std::vector> table; static constexpr double max_ratio = 0.7; static constexpr int init_size = 8; void expand() { _size_mod = _size_mod * 2 + 1; std::vector> tmp(_size_mod + 1, {_NULL, _ERASED}); std::swap(tmp, table); _cnt_data = 0; for (auto [key, val] : tmp) { if (key != _NULL && val != _ERASED) { emplace(key, val); } } } public: hash_map() : _size_mod(init_size - 1), _cnt_data(0), table(_size_mod + 1, {_NULL, _ERASED}) {} hash_map(int size) : _size_mod(bit_ceil(size) - 1), _cnt_data(0), table(_size_mod + 1, {_NULL, _ERASED}) {} // {追加することができたか、追加後のtable[x]の参照} std::pair emplace(S x, T y) { if (max_ratio * _size_mod < _cnt_data) expand(); int i = hash_fast::hash(x) & _size_mod; while (table[i].first != _NULL) { if (table[i].first == x) { if (table[i].second == _ERASED) { table[i].second = y; return {true, table[i].second}; } else { return {false, table[i].second}; } } i = (i + 1) & _size_mod; } table[i] = {x, y}; _cnt_data++; return {true, table[i].second}; } // emplaceを行った後にtable[x]をyにする // {table[x]が存在しなかったらtrue、追加後のtable[x]の参照} std::pair emplace_replace(S x, T y) { if (max_ratio * _size_mod < _cnt_data) expand(); int i = hash_fast::hash(x) & _size_mod; while (table[i].first != _NULL) { if (table[i].first == x) { bool f = table[i].second == _ERASED; table[i].second = y; return {f, table[i].second}; } i = (i + 1) & _size_mod; } table[i] = {x, y}; _cnt_data++; return {true, table[i].second}; } // 削除することができたか bool erase(S x) { int i = hash_fast::hash(x) & _size_mod; while (table[i].first != _NULL) { if (table[i].first == x) { bool f = table[i].second != _ERASED; table[i].second = _NULL; return f; } i = (i + 1) & _size_mod; } return false; } // {存在するか、存在する場合その値の参照} std::pair find(S x) { int i = hash_fast::hash(x) & _size_mod; while (table[i].first != _NULL) { if (table[i].first == x) { return {table[i].second != _ERASED, table[i].second}; } i = (i + 1) & _size_mod; } return {false, table[i].second}; } }; template std::vector enumerate_quotients(T x) { assert(x >= 0); if (x == 0) return {}; T sq = sqrtl(x); std::vector ans(sq); std::iota(ans.begin(), ans.end(), 1); if (x / sq == sq) sq--; for (T i = sq; i >= 1; i--) ans.push_back(x / i); return ans; } long long counting_primes(long long n) { assert(n >= 0); if (n == 0) return 0; int sq = sqrt(n); std::vector is_prime(sq + 1, true); std::vector Fprime(sq + 1, 0); is_prime[0] = is_prime[1] = false; for (int p = 2; p <= sq; p++) { Fprime[p] = Fprime[p - 1] + is_prime[p]; if (!is_prime[p]) continue; for (int i = 2 * p; i <= sq; i += p) is_prime[i] = false; } auto Q = enumerate_quotients(n); int W = Q.size(); std::vector f(W); for (int i = 0; i < W; i++) f[i] = Q[i] - 1; for (int p = 2; p <= sq; p++) { if (!is_prime[p]) continue; long long p2 = (long long)p * p; if (p2 <= sq) { for (int i = W - 1, j = W - 1; i >= 0 && Q[i] >= p2; i--) { while (j >= 0 && Q[j] > Q[i] / p) j--; f[i] -= f[j] - Fprime[p - 1]; } } else { for (int i = W - 1; i >= 0 && Q[i] >= p2; i--) { long long x = Q[i] / p; int j = (x <= sq ? x - 1 : W - n / x); f[i] -= f[j] - Fprime[p - 1]; } } } return f[W - 1]; } long long prefixsum_primes(long long n) { assert(n >= 0); if (n == 0) return 0; int sq = sqrt(n); std::vector is_prime(sq + 1, true); std::vector Fprime(sq + 1, 0); is_prime[0] = is_prime[1] = false; for (int p = 2; p <= sq; p++) { Fprime[p] = Fprime[p - 1] + (is_prime[p] ? p : 0); if (!is_prime[p]) continue; for (int i = 2 * p; i <= sq; i += p) is_prime[i] = false; } auto Q = enumerate_quotients(n); int W = Q.size(); std::vector f(W); for (int i = 0; i < W; i++) f[i] = (Q[i] * (Q[i] + 1)) / 2 - 1; for (int p = 2; p <= sq; p++) { if (!is_prime[p]) continue; long long p2 = (long long)p * p; if (p2 <= sq) { for (int i = W - 1, j = W - 1; i >= 0 && Q[i] >= p2; i--) { while (j >= 0 && Q[j] > Q[i] / p) j--; f[i] -= p * (f[j] - Fprime[p - 1]); } } else { for (int i = W - 1; i >= 0 && Q[i] >= p2; i--) { long long x = Q[i] / p; int j = (x <= sq ? x - 1 : W - n / x); f[i] -= p * (f[j] - Fprime[p - 1]); } } } return f[W - 1]; } int main() { long long N; std::cin >> N; std::cout << prefixsum_primes(N) << '\n'; }