Skip to content

http://poj.openjudge.cn/practice/C26E/

C++
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using u64 = unsigned long long;
using u128 = __uint128_t;

const ll INF = (ll)4e18;

const int SIEVE_MAX = 5000000;
const int PHI_X = 100000;
const int PHI_A = 100;

vector<int> primes;
vector<int> pi_pref;
vector<unsigned char> comp;

static int phi_tbl[PHI_A + 1][PHI_X + 1];

void sieve() {
    comp.assign(SIEVE_MAX + 1, 0);
    pi_pref.assign(SIEVE_MAX + 1, 0);

    for (int i = 2; i <= SIEVE_MAX; ++i) {
        if (!comp[i]) primes.push_back(i);

        for (int p : primes) {
            long long v = 1LL * i * p;
            if (v > SIEVE_MAX) break;

            comp[(int)v] = 1;
            if (i % p == 0) break;
        }
    }

    int cnt = 0;
    for (int i = 0; i <= SIEVE_MAX; ++i) {
        if (i >= 2 && !comp[i]) ++cnt;
        pi_pref[i] = cnt;
    }
}

void init_phi_table() {
    for (int x = 0; x <= PHI_X; ++x) phi_tbl[0][x] = x;

    for (int a = 1; a <= PHI_A; ++a) {
        int p = primes[a - 1];
        for (int x = 0; x <= PHI_X; ++x) {
            phi_tbl[a][x] = phi_tbl[a - 1][x] - phi_tbl[a - 1][x / p];
        }
    }
}

ll isqrt_ll(ll x) {
    ll r = sqrt((long double)x);
    while ((r + 1) <= x / (r + 1)) ++r;
    while (r > x / r) --r;
    return r;
}

ll icbrt_ll(ll x) {
    ll r = cbrt((long double)x);
    while ((u128)(r + 1) * (r + 1) * (r + 1) <= (u64)x) ++r;
    while ((u128)r * r * r > (u64)x) --r;
    return r;
}

ll i4rt_ll(ll x) {
    ll r = sqrt(sqrt((long double)x));

    auto fourth = [](ll v) -> u128 {
        return (u128)v * v * v * v;
    };

    while (fourth(r + 1) <= (u64)x) ++r;
    while (fourth(r) > (u64)x) --r;
    return r;
}

ll prime_pi(ll x);

ll phi_count(ll x, int a) {
    if (x == 0) return 0;
    if (a == 0) return x;

    if (a <= PHI_A && x <= PHI_X) {
        return phi_tbl[a][(int)x];
    }

    if (a - 1 < (int)primes.size() && primes[a - 1] >= x) {
        return 1;
    }

    if (a < (int)primes.size() && 1LL * primes[a] * primes[a] > x) {
        return prime_pi(x) - a + 1;
    }

    ll res = x;
    for (int i = 0; i < a; ++i) {
        res -= phi_count(x / primes[i], i);
    }

    return res;
}

unordered_map<ll, ll> pi_cache;

ll prime_pi(ll x) {
    if (x <= SIEVE_MAX) return pi_pref[(int)x];

    auto it = pi_cache.find(x);
    if (it != pi_cache.end()) return it->second;

    ll a = prime_pi(i4rt_ll(x));
    ll b = prime_pi(isqrt_ll(x));
    ll c = prime_pi(icbrt_ll(x));

    ll sum = phi_count(x, (int)a) + (b + a - 2) * (b - a + 1) / 2;

    for (ll i = a; i < b; ++i) {
        ll w = x / primes[(size_t)i];

        sum -= prime_pi(w);

        if (i < c) {
            ll lim = prime_pi(isqrt_ll(w));
            for (ll j = i; j < lim; ++j) {
                sum -= prime_pi(w / primes[(size_t)j]) - j;
            }
        }
    }

    pi_cache[x] = sum;
    return sum;
}

ll mod_pow(ll a, ll d, ll mod) {
    u128 res = 1;
    u128 base = (u64)a % (u64)mod;

    while (d) {
        if (d & 1) res = res * base % (u64)mod;
        base = base * base % (u64)mod;
        d >>= 1;
    }

    return (ll)res;
}

bool is_prime64(ll n) {
    if (n < 2) return false;

    for (ll p : {2LL, 3LL, 5LL, 7LL, 11LL, 13LL, 17LL, 19LL, 23LL, 29LL, 31LL, 37LL}) {
        if (n % p == 0) return n == p;
    }

    ll d = n - 1;
    ll s = 0;

    while ((d & 1) == 0) {
        d >>= 1;
        ++s;
    }

    for (ll a : {2LL, 3LL, 5LL, 7LL, 11LL, 13LL, 17LL, 19LL, 23LL, 29LL, 31LL, 37LL}) {
        if (a >= n) continue;

        ll x = mod_pow(a, d, n);
        if (x == 1 || x == n - 1) continue;

        bool composite = true;

        for (int r = 1; r < s; ++r) {
            x = (ll)((u128)x * x % (u64)n);
            if (x == n - 1) {
                composite = false;
                break;
            }
        }

        if (composite) return false;
    }

    return true;
}

ll next_prime_gt_half(ll x) {
    ll v = x / 2 + 1;

    if (v <= 2) return 2;
    if ((v & 1) == 0) ++v;

    while (!is_prime64(v)) v += 2;

    return v;
}

unordered_map<ll, ll> g_cache;

ll get_g(ll x) {
    if (x == 1) return INF;

    auto it = g_cache.find(x);
    if (it != g_cache.end()) return it->second;

    for (int p : primes) {
        if (1LL * p * p > x) break;

        if ((ll)p < get_g(x / p)) {
            g_cache[x] = p;
            return p;
        }
    }

    ll ret = next_prime_gt_half(x);
    g_cache[x] = ret;
    return ret;
}

ll count_spf_less(ll m, ll t) {
    if (m <= 1 || t <= 2) return 0;

    if (t >= INF / 2 || t > m) {
        return m - 1;
    }

    int a;

    if (t - 1 <= SIEVE_MAX) {
        a = pi_pref[(int)(t - 1)];
    } else {
        a = (int)prime_pi(t - 1);
    }

    return m - phi_count(m, a);
}

ll solve(ll n) {
    if (n == 1) return 1;

    g_cache.clear();
    g_cache.reserve(1 << 20);

    ll ans = 0;

    for (ll l = 1; l <= n; ) {
        ll x = n / l;
        ll r = n / x;

        ll t = get_g(x);

        ans += count_spf_less(r, t) - count_spf_less(l - 1, t);

        l = r + 1;
    }

    return ans;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    sieve();
    init_phi_table();

    pi_cache.reserve(1 << 16);

    ll n;
    cin >> n;

    cout << solve(n) << '\n';

    return 0;
}