Prefix sums of multiplicative or prime-supported functions for up to –, all built on the floor-value set of size (Floor Sums).

MethodComputesTimeSpace
Lucy (Legendre / Meissel style),
Min_25, multiplicative with a low-degree polynomial (practical to )
Du’s sieve when and have easy prefix sums
powerful-number trick when agrees with an easy on primes plus evaluations
squarefree count
Meissel–Lehmer / LMO to +

Lucy’s prime counting

= numbers in that are prime or have smallest prime factor . Start with and, for each prime in increasing order, remove the numbers whose smallest prime factor is exactly : for every . At the end for all floor values . Weighting by gives prime power sums.

struct Lucy {                                              // pi(v) for every v in {floor(n / i)}
    ll n, r; vector<ll> V, S; vector<int> lo, hi;
    int id(ll v) const { return v <= r ? lo[v] : hi[n / v]; }
    Lucy(ll n) : n(n) {
        r = sqrtl(n); while (r * r > n) r--; while ((r + 1) * (r + 1) <= n) r++;
        lo.assign(r + 2, 0); hi.assign(r + 2, 0);
        for (ll l = 1; l <= n; l = n / (n / l) + 1) { ll v = n / l; (v <= r ? lo[v] : hi[n / v]) = sz(V); V.push_back(v); S.push_back(v - 1); }
        for (ll p = 2; p <= r; p++) {
            if (S[id(p)] == S[id(p - 1)]) continue;         // p is not prime
            ll sp = S[id(p - 1)], p2 = p * p;
            for (int i = 0; i < sz(V) && V[i] >= p2; i++) S[i] -= S[id(V[i] / p)] - sp;   // V is decreasing
        }
    }
    ll pi(ll v) const { return S[id(v)]; }
};

Min_25 sieve

For multiplicative whose value on primes is a polynomial and with computable: phase 1 runs Lucy for each power to get at all floor values; phase 2 adds composites by smallest prime factor:
, and .

template <class FPE> mint min25(ll n, const vector<mint>& coef, FPE fpe) {   // f(p) = sum coef[k] p^k; fpe(p, e) = f(p^e)
    ll r = sqrtl(n); while (r * r > n) r--; while ((r + 1) * (r + 1) <= n) r++;
    vector<ll> V; vector<int> lo(r + 2), hi(r + 2);
    for (ll l = 1; l <= n; l = n / (n / l) + 1) { ll v = n / l; (v <= r ? lo[v] : hi[n / v]) = sz(V); V.push_back(v); }
    auto id = [&](ll v) { return v <= r ? lo[v] : hi[n / v]; };
    vector<int> primes; { vector<char> c(r + 1); for (ll i = 2; i <= r; i++) if (!c[i]) { primes.push_back(i); for (ll j = i * i; j <= r; j += i) c[j] = 1; } }
    int K = sz(coef); vector<mint> G(sz(V), 0);
    for (int k = 0; k < K; k++) {                          // Lucy on p^k: g(v) = sum_{2 <= i <= v} i^k, then sieve
        vector<mint> g(sz(V));
        for (int i = 0; i < sz(V); i++) {
            mint v = V[i];
            if (k == 0) g[i] = v - 1; else if (k == 1) g[i] = v * (v + 1) / 2 - 1; else g[i] = v * (v + 1) * (2 * v + 1) / 6 - 1;
        }
        vector<mint> pp(sz(primes) + 1, 0);
        for (int j = 0; j < sz(primes); j++) pp[j + 1] = pp[j] + mint(primes[j]).pow(k);
        for (int j = 0; j < sz(primes); j++) {
            ll p = primes[j]; mint pk = mint(p).pow(k);
            for (int i = 0; i < sz(V) && V[i] >= p * p; i++) g[i] -= pk * (g[id(V[i] / p)] - pp[j]);
        }
        for (int i = 0; i < sz(V); i++) G[i] += coef[k] * g[i];
    }
    vector<mint> Gp(sz(primes) + 1, 0);                    // sum of f(p) over the first j primes
    for (int j = 0; j < sz(primes); j++) { mint s = 0, pw = 1; for (int k = 0; k < K; k++) s += coef[k] * pw, pw *= primes[j]; Gp[j + 1] = Gp[j] + s; }
    auto S = [&](auto& self, ll x, int j) -> mint {        // sum of f(i) over 2 <= i <= x with spf(i) >= primes[j]
        if (j < sz(primes) && primes[j] > x) return 0;
        mint res = G[id(x)] - Gp[j];
        for (int k = j; k < sz(primes) && (ll)primes[k] * primes[k] <= x; k++) {
            ll p = primes[k], pe = p;
            for (int e = 1; pe * p <= x; e++, pe *= p) res += fpe(p, e) * self(self, x / pe, k + 1) + fpe(p, e + 1);
        }
        return res;
    };
    return S(S, n, 0) + 1;                                 // + f(1)
}

Supported directly: (: coef = {-1, 1}), ({-1}), ({1, 1}), ({2}), sums of primes ({0, 1} with phase 1 only). Powers up to are built in; add more power-sum formulas for higher degrees.

Du’s sieve (generic)

If with prefix sums , cheap: . Sieve up to , memoise above. The concrete / Mertens version is in Arithmetic Functions.

template <class T> struct DuGeneric {                      // small[x] = S_f(x) for x <= L; Sg, Sh prefix sums of g, h; g(1) = 1
    vector<T> small; function<T(ll)> Sg, Sh; unordered_map<ll, T> memo;
    T operator()(ll n) {
        if (n < sz(small)) return small[n];
        if (auto it = memo.find(n); it != memo.end()) return it->second;
        T r = Sh(n);
        for (ll l = 2, rr; l <= n; l = rr + 1) { rr = n / (n / l); r -= (Sg(rr) - Sg(l - 1)) * (*this)(n / l); }
        return memo[n] = r;
    }
};

Powerful-number trick

If is multiplicative and is multiplicative with on primes and an easy prefix sum , then vanishes on non-powerful numbers (every prime exponent ), so ; there are only powerful numbers up to , enumerated by DFS over primes . comes from .

template <class FPE, class GPE, class GS> mint powerfulSum(ll n, FPE fpe, GPE gpe, GS G) {
    ll r = sqrtl(n); while (r * r > n) r--; while ((r + 1) * (r + 1) <= n) r++;
    vector<int> pr; { vector<char> c(r + 1); for (ll i = 2; i <= r; i++) if (!c[i]) { pr.push_back(i); for (ll j = i * i; j <= r; j += i) c[j] = 1; } }
    mint res = 0;
    auto dfs = [&](auto& self, int k, ll d, mint hd) -> void {   // d powerful, h(d) = hd; primes from index k on
        res += hd * G(n / d);
        for (int j = k; j < sz(pr) && (i128)d * pr[j] * pr[j] <= n; j++) {
            ll p = pr[j]; vector<mint> h{1};               // h(p^0..)
            ll pe = p * p;
            for (int e = 2; (i128)d * pe <= n; e++, pe *= p) {
                while (sz(h) <= e) { int t = sz(h); mint v = fpe(p, t); for (int i = 1; i <= t; i++) v -= gpe(p, i) * h[t - i]; h.push_back(v); }
                if (h[e] != mint(0)) self(self, j + 1, d * pe, hd * h[e]);
                if ((i128)pe * p > n) break;
            }
        }
    };
    dfs(dfs, 0, 1, 1);
    return res;
}
ll squarefreeCount(ll n) {                                 // sum_{d <= sqrt n} mu(d) floor(n / d^2)
    ll r = sqrtl(n); while (r * r > n) r--; while ((r + 1) * (r + 1) <= n) r++;
    vector<int> mu(r + 1, 1), mark(r + 1); ll res = 0;
    for (ll i = 2; i <= r; i++) if (!mark[i]) for (ll j = i; j <= r; j += i) { mark[j] = 1; mu[j] = (j / i) % i == 0 ? 0 : -mu[j]; }
    for (ll d = 1; d <= r; d++) res += mu[d] * (n / (d * d));
    return res;
}