#include <bits/stdtr1c++.h>

#define MAXN 100
#define MAXM 100010
#define MAXP 10000010

using namespace std;

int prime_cnt[MAXP];
long long dp[MAXN][MAXM];

vector<int> primes;
bitset<MAXP> is_prime;

void sieve(){
    is_prime[2] = true;
    for (int i = 3; i < MAXP; i += 2) is_prime[i] = true;

    for (int i = 3; i * i < MAXP; i += 2){
        for (int j = i * i; is_prime[i] && j < MAXP; j += (i << 1)){
            is_prime[j] = false;
        }
    }

    for (int i = 1; i < MAXP; i++){
        prime_cnt[i] = prime_cnt[i - 1] + is_prime[i];
        if (is_prime[i]) primes.push_back(i);
    }
}

void gen(){
    sieve();

    for (int m = 0; m < MAXM; m++) dp[0][m] = m;
    for (int n = 1; n < MAXN; n++){
        for (int m = 0; m < MAXM; m++){
            dp[n][m] = dp[n - 1][m] - dp[n - 1][m / primes[n - 1]];
        }
    }
}

long long phi(long long m, int n){
    if (n == 0) return m;
    if (m < MAXM && n < MAXN) return dp[n][m];
    if ((long long)primes[n - 1] * primes[n - 1] >= m && m < MAXP) return prime_cnt[m] - n + 1;

    return phi(m, n - 1) - phi(m / primes[n - 1], n - 1);
}

long long lehmer(long long m){
    if (m < MAXP) return prime_cnt[m];

    int s = sqrt(0.5 + m), y = cbrt(0.5 + m);
    int a = prime_cnt[y];

    long long res = phi(m, a) + a - 1;
    for (int i = a; primes[i] <= s; i++){
        res = res - lehmer(m / primes[i]) + lehmer(primes[i]) - 1;
    }
    return res;
}

int main(){
    auto start = clock();
    gen();
    printf("Time taken to generate = %0.6f\n\n", (clock() - start) / (double)CLOCKS_PER_SEC);

    cout << lehmer(1e12) << endl;
    printf("\nTime taken = %0.6f\n", (clock() - start) / (double)CLOCKS_PER_SEC);

    return 0;
}
