#pragma region Macros #include #define ll long long #define ld long double #define rep2(i, a, b) for(ll i = a; i <= b; ++i) #define rep(i, n) for(ll i = 0; i < n; ++i) #define rep3(i, a, b) for(ll i = a; i >= b; --i) #define pii pair #define pll pair #define pb push_back #define eb emplace_back #define vi vector #define vll vector #define vpi vector #define vpll vector #define overload2(_1, _2, name, ...) name #define vec(type, name, ...) vector name(__VA_ARGS__) #define VEC(type, name, size) \ vector name(size); \ IN(name) #define vv(type, name, h, ...) vector> name(h, vector(__VA_ARGS__)) #define VV(type, name, h, w) \ vector> name(h, vector(w)); \ IN(name) #define vvv(type, name, h, w, ...) vector>> name(h, vector>(w, vector(__VA_ARGS__))) #define vvvv(type, name, a, b, c, ...) \ vector>>> name(a, vector>>(b, vector>(c, vector(__VA_ARGS__)))) #define mt make_tuple #define fi first #define se second #define all(c) begin(c), end(c) #define lb(c, x) distance((c).begin(), lower_bound(all(c), (x))) #define ub(c, x) distance((c).begin(), upper_bound(all(c), (x))) using namespace std; constexpr pii dx4[4] = {pii{1, 0}, pii{0, 1}, pii{-1, 0}, pii{0, -1}}; constexpr pii dx8[8] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}}; const string YESNO[2] = {"NO", "YES"}; const string YesNo[2] = {"No", "Yes"}; const string yesno[2] = {"no", "yes"}; void YES(bool t = 1) { cout << YESNO[t] << endl; } void Yes(bool t = 1) { cout << YesNo[t] << endl; } void yes(bool t = 1) { cout << yesno[t] << endl; } template using vc = vector; template using vvc = vector>; template using vvvc = vector>; template using vvvvc = vector>; template using pq = priority_queue; template using pqg = priority_queue, greater>; #define si(c) (int)(c).size() #define INT(...) \ int __VA_ARGS__; \ IN(__VA_ARGS__) #define LL(...) \ ll __VA_ARGS__; \ IN(__VA_ARGS__) #define STR(...) \ string __VA_ARGS__; \ IN(__VA_ARGS__) #define CHR(...) \ char __VA_ARGS__; \ IN(__VA_ARGS__) #define DBL(...) \ double __VA_ARGS__; \ IN(__VA_ARGS__) int scan() { return getchar(); } void scan(int &a) { cin >> a; } void scan(long long &a) { cin >> a; } void scan(char &a) { cin >> a; } void scan(double &a) { cin >> a; } void scan(string &a) { cin >> a; } template void scan(pair &p) { scan(p.first), scan(p.second); } template void scan(vector &); template void scan(vector &a) { for(auto &i : a) scan(i); } template void scan(T &a) { cin >> a; } void IN() {} template void IN(Head &head, Tail &... tail) { scan(head); IN(tail...); } template inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); } template inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); } vi iota(int n) { vi a(n); iota(all(a), 0); return a; } template vi iota(vector &a, bool greater = false) { vi res(a.size()); iota(all(res), 0); sort(all(res), [&](int i, int j) { if(greater) return a[i] > a[j]; return a[i] < a[j]; }); return res; } #define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end()) template T POW(T x, int n) { T res = 1; for(; n; n >>= 1, x *= x) if(n & 1) res *= x; return res; } vector factor(ll x) { vector ans; for(ll i = 2; i * i <= x; i++) if(x % i == 0) { ans.push_back({i, 1}); while((x /= i) % i == 0) ans.back().second++; } if(x != 1) ans.push_back({x, 1}); return ans; } template vector divisor(T x) { vector ans; for(T i = 1; i * i <= x; i++) if(x % i == 0) { ans.pb(i); if(i * i != x) ans.pb(x / i); } return ans; } template void zip(vector &x) { vector y = x; sort(all(y)); for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); } } int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); } int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); } int botbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); } int botbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); } int allbit(int n) { return (1 << n) - 1; } int popcount(signed t) { return __builtin_popcount(t); } int popcount(ll t) { return __builtin_popcountll(t); } bool ispow2(int i) { return i && (i & -i) == i; } int in() { int x; cin >> x; return x; } ll lin() { unsigned long long x; cin >> x; return x; } template pair operator-(const pair &x, const pair &y) { return pair(x.fi - y.fi, x.se - y.se); } template pair operator+(const pair &x, const pair &y) { return pair(x.fi + y.fi, x.se + y.se); } template ll operator*(const pair &x, const pair &y) { return (ll)x.fi * y.fi + (ll)x.se * y.se; } template struct edge { int from, to; T cost; int id; edge(int to, T cost) : from(-1), to(to), cost(cost) {} edge(int from, int to, T cost) : from(from), to(to), cost(cost) {} edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {} edge &operator=(const int &x) { to = x; return *this; } operator int() const { return to; } }; template using Edges = vector>; using Tree = vector>; using Graph = vector>; template using Wgraph = vector>>; Graph getG(int n, int m = -1, bool directed = false, int margin = 1) { Tree res(n); if(m == -1) m = n - 1; while(m--) { int a, b; cin >> a >> b; a -= margin, b -= margin; res[a].emplace_back(b); if(!directed) res[b].emplace_back(a); } return move(res); } template Wgraph getWg(int n, int m = -1, bool directed = false, int margin = 1) { Wgraph res(n); if(m == -1) m = n - 1; while(m--) { int a, b; T c; cin >> a >> b >> c; a -= margin, b -= margin; res[a].emplace_back(b, c); if(!directed) res[b].emplace_back(a, c); } return move(res); } #define i128 __int128_t #define ull unsigned long long int #define TEST \ INT(testcases); \ while(testcases--) template ostream &operator<<(ostream &os, const vector &v) { for(auto it = begin(v); it != end(v); ++it) { if(it == begin(v)) os << *it; else os << " " << *it; } return os; } template ostream &operator<<(ostream &os, const pair &p) { os << p.first << " " << p.second; return os; } template string to_string(pair p) { return "(" + to_string(p.first) + "," + to_string(p.second) + ")"; } template string to_string(A v) { if(v.empty()) return "{}"; string ret = "{"; for(auto &x : v) ret += to_string(x) + ","; ret.back() = '}'; return ret; } void dump() { cerr << endl; } template void dump(Head head, Tail... tail) { cerr << to_string(head) << " "; dump(tail...); } #define endl '\n' #ifdef _LOCAL #undef endl #define debug(x) \ cout << #x << ": "; \ dump(x) #else #define debug(x) #endif template static constexpr T inf = numeric_limits::max() / 2; struct Setup_io { Setup_io() { ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0); cout << fixed << setprecision(15); } } setup_io; #define drop(s) cout << #s << endl, exit(0) #pragma endregion // from https://judge.yosupo.jp/submission/5147 vector prime_sieve(const int N, const int Q = 17, const int L = 1 << 15) { using u8 = unsigned char; static const int rs[] = {1, 7, 11, 13, 17, 19, 23, 29}; struct P { P(int p) : p(p) {} int p; int pos[8]; }; auto approx_prime_count = [](const int N) -> int { return N > 60184 ? N / (log(N) - 1.1) : max(1., N / (log(N) - 1.11)) + 1; }; const int v = sqrt(N), vv = sqrt(v); vector isp(v + 1, true); for(int i = 2; i <= vv; ++i) if(isp[i]) { for(int j = i * i; j <= v; j += i) isp[j] = false; } const int rsize = approx_prime_count(N + 30); vector primes = {2, 3, 5}; int psize = 3; primes.resize(rsize); vector

sprimes; size_t pbeg = 0; int prod = 1; for(int p = 7; p <= v; ++p) { if(!isp[p]) continue; if(p <= Q) prod *= p, ++pbeg, primes[psize++] = p; auto pp = P(p); for(int t = 0; t < 8; ++t) { int j = (p <= Q) ? p : p * p; while(j % 30 != rs[t]) j += p << 1; pp.pos[t] = j / 30; } sprimes.push_back(pp); } vector pre(prod, 0xFF); for(size_t pi = 0; pi < pbeg; ++pi) { auto pp = sprimes[pi]; const int p = pp.p; for(int t = 0; t < 8; ++t) { const u8 m = ~(1 << t); for(int i = pp.pos[t]; i < prod; i += p) pre[i] &= m; } } const int block_size = (L + prod - 1) / prod * prod; vector block(block_size); u8 *pblock = block.data(); const int M = (N + 29) / 30; for(int beg = 0; beg < M; beg += block_size, pblock -= block_size) { int end = min(M, beg + block_size); for(int i = beg; i < end; i += prod) { copy(pre.begin(), pre.end(), pblock + i); } if(beg == 0) pblock[0] &= 0xFE; for(size_t pi = pbeg; pi < sprimes.size(); ++pi) { auto &pp = sprimes[pi]; const int p = pp.p; for(int t = 0; t < 8; ++t) { int i = pp.pos[t]; const u8 m = ~(1 << t); for(; i < end; i += p) pblock[i] &= m; pp.pos[t] = i; } } for(int i = beg; i < end; ++i) { for(int m = pblock[i]; m > 0; m &= m - 1) { primes[psize++] = i * 30 + rs[__builtin_ctz(m)]; } } } assert(psize <= rsize); while(psize > 0 && primes[psize - 1] > N) --psize; primes.resize(psize); return primes; } ll prime_pi(const ll n) { if(n <= 1) return 0; if(n == 2) return 1; const int sq = sqrtl(n); int s = 1 + sq >> 1; vector smalls(s); for(int i = 1; i < s; ++i) smalls[i] = i; vector roughs(s); for(int i = 0; i < s; ++i) roughs[i] = i << 1 | 1; vector larges(s); for(int i = 0; i < s; ++i) larges[i] = (n / (i << 1 | 1) - 1) >> 1; vector skip(sq + 1); const auto divide = [](ll n, ll d) -> int { return (long double)n / d; }; const auto half = [](int n) -> int { return (n - 1) >> 1; }; int pc = 0; for(int p = 3; p <= sq; p += 2) if(!skip[p]) { int q = p * p; if((ll)q * q > n) break; skip[p] = true; for(int i = q; i <= sq; i += p << 1) skip[i] = true; int ns = 0; for(int k = 0; k < s; ++k) { int i = roughs[k]; if(skip[i]) continue; ll d = (ll)i * p; larges[ns] = larges[k] - (d <= sq ? larges[smalls[d >> 1] - pc] : smalls[half(divide(n, d))]) + pc; roughs[ns++] = i; } s = ns; for(int i = half(sq), j = ((sq / p) - 1) | 1; j >= p; j -= 2) { int c = smalls[j >> 1] - pc; for(int e = (j * p) >> 1; i >= e; --i) smalls[i] -= c; } ++pc; } larges[0] += (ll)(s + 2 * (pc - 1)) * (s - 1) / 2; for(int k = 1; k < s; ++k) larges[0] -= larges[k]; for(int l = 1; l < s; ++l) { int q = roughs[l]; ll m = n / q; int e = smalls[half(m / q)] - pc; if(e < l + 1) break; ll t = 0; for(int k = l + 1; k <= e; ++k) t += smalls[half(divide(m, roughs[k]))]; larges[0] += t - (ll)(e - l) * (pc + l - 1); } return larges[0] + 1; } int main() { LL(n); ll ans = 0; const int N = 10000000, M = 110000; auto P = prime_sieve(N); vector cnt(N + 1); for(auto e : P) cnt[e] = 1; rep(i, N) cnt[i + 1] += cnt[i]; unordered_map mem; auto prime_count = [&](ll x) -> ll { if(x > N) { if(mem.count(x)) return mem[x]; return mem[x] = prime_pi(x); } return cnt[x]; }; auto primes = prime_sieve(M); vector> dp(si(primes)); auto rec = [&](auto &&self, int i, ll x) -> ll { if(dp[i].count(x)) return dp[i][x]; auto &res = dp[i][x]; if((ll)primes[i] * (primes[i] - 1) > x) { res = prime_count(x + 1) - i + 1; chmax(res, 1); return res; } else { res = self(self, i + 1, x); x /= primes[i] - 1; while(x) { res += self(self, i + 1, x); x /= primes[i]; } return res; } }; cout << rec(rec, 0, n) << endl; }