library

This documentation is automatically generated by online-judge-tools/verification-helper


Project maintained by tko919 Hosted on GitHub Pages — Theme by mattgraham

:warning: Multiplicative Sum $O(n^{2/3}(\log n)^{-1})$
(Math/multiplicative2.hpp)

Depends on

Code

#pragma once
#include "Math/sieve.hpp"

template <typename T> struct Dir {
    ll n;
    int SQ, sz;
    vector<T> dat;
    Dir() {}
    Dir(ll n) : n(n), SQ(sqrtl(n)), sz(SQ + n / (SQ + 1) + 1), dat(sz) {}
    T &operator[](int i) {
        return dat[i];
    }
    void pref() {
        rep(i, 0, sz - 1) dat[i + 1] += dat[i];
    }
    void diff() {
        rrep(i, 0, sz - 1) dat[i + 1] -= dat[i];
    }
    int idx(ll x) const {
        return (x <= SQ ? x : sz - n / x);
    }
    ll val(int id) const {
        return (id <= SQ ? id : n / (sz - id));
    }
};

template <typename T> Dir<T> mult(ll n, Dir<T> &a, Dir<T> &b) {
    int SQ = sqrtl(n);
    Dir<T> c(n);
    int thre = a.idx(max<int>(1, pow(n, 2. / 3)));
    auto get = [&](Dir<T> &A, Dir<T> &B) -> vector<pair<int, T>> {
        vector<pair<int, T>> ret;
        rep(i, 1, SQ + 1) if (A[i - 1] != A[i]) {
            T x = A[i] - A[i - 1];
            ret.push_back({i, x});
            rrep(j, thre + 1, c.sz) {
                ll k = c.val(j);
                int to = B.idx(k / i);
                if (to < i)
                    break;
                c[j] += x * B[to];
            }
        }
        rep(i, SQ + 1, thre + 1) {
            if (A[i - 1] != A[i]) {
                T x = A[i] - A[i - 1];
                ret.push_back({A.val(i), x});
            }
        }
        return ret;
    };
    auto posA = get(a, b);
    auto posB = get(b, a);
    for (auto &[v, x] : posA) {
        for (auto &[w, y] : posB) {
            int to = c.idx(ll(v) * w);
            if (to > thre)
                break;
            c[c.idx(v * w)] += x * y;
        }
    }
    rep(i, 1, thre + 1) {
        c[i] += c[i - 1];
    }

    rrep(i, thre + 1, c.sz) {
        ll x = c.val(i);
        int j = sqrtl(x);
        c[i] -= a[j] * b[j];
    }

    return c;
}

template <typename T, T (*F)(ll)> Dir<T> getLarge(ll n) {
    Dir<T> base(n);
    int SQ = sqrtl(n);
    auto ps = sieve(SQ);
    vector<T> small(SQ + 10);
    rep(x, 1, SQ + 10) small[x] = F(x);
    rrep(i, 1, SQ + 10) small[i] -= small[i - 1];
    Dir<T> den(n), lg(n);

    int SQ6 = max<int>(1, pow(n, 1. / 6));
    for (auto &p : ps)
        if (SQ6 < p) {
            T f_p = small[p];
            T X[10] = {}, base[10] = {};
            rep(i, 1, 10) {
                base[i] = POW<T>(f_p, i);
            }
            rep(i, 1, 10) {
                T tmp = base[i] * i;
                rep(j, 1, i + 1) tmp -= base[j] * X[i - j];
                X[i] = tmp;
            }
            rep(i, 1, 10) X[i] /= i;

            for (ll x = 1, i = 0;; x *= p, i++) {
                lg[den.idx(x)] += X[i];
                if (x > n / p)
                    break;
            }
        }
    lg.pref();

    // exp
    {
        Dir<T> add(n);
        rep(i, 1, add.sz) add[i] = den[i] = 1;
        rep(e, 1, 5 + 1) {
            add = mult(n, add, lg);
            rep(i, 1, add.sz) den[i] += add[i] * Fact<T>(e, 1);
        }
    }

    for (auto &p : ps)
        if (p <= SQ6) {
            T f_p = small[p];
            rep(i, 1, den.sz) {
                ll x = den.val(i);
                den[i] += den[den.idx(x / p)] * f_p;
            }
        }

    Dir<T> ret(n);
    rrep(i, 1, SQ + 1) if (n / i > SQ) {
        int id = den.idx(n / i);
        T tmp = F(n / i) - den[id];
        for (int j = 2; i * j <= SQ; j++)
            tmp -= small[j] * ret[ret.idx(n / i / j)];
        ret[id] = tmp;
    }

    ret.diff();
    return ret;
}

template <typename T, T (*pe)(int p, int e)>
Dir<T> MultiplicativeSum(ll n, Dir<T> &large) {
    Dir<T> base(n), lg(n);
    int SQ = sqrtl(n);
    auto ps = sieve(SQ);

    int SQ6 = max<int>(1, pow(n, 1. / 6));
    for (auto &p : ps) {
        if (p <= SQ6)
            continue;
        T X[10] = {}, base[10] = {};
        rep(i, 1, 10) {
            base[i] = pe(p, i);
        }
        rep(i, 1, 10) {
            T tmp = base[i] * i;
            rep(j, 1, i + 1) tmp -= base[j] * X[i - j];
            X[i] = tmp;
        }
        rep(i, 1, 10) X[i] /= i;
        for (ll x = 1, i = 0;; x *= p, i++) {
            lg[lg.idx(x)] += X[i];
            if (x > n / p)
                break;
        }
    }
    lg.pref();

    // exp
    {
        Dir<T> add(n);
        rep(i, 1, add.sz) add[i] = base[i] = 1;
        rep(e, 1, 5 + 1) {
            add = mult(n, add, lg);
            rep(i, 1, add.sz) base[i] += add[i] * Fact<T>(e, 1);
        }
    }

    rrep(x, 1, SQ + 1) {
        int i = base.idx(n / x);
        for (int y = 1; x * y <= SQ; y++)
            if (base[y - 1] != base[y]) {
                base[i] +=
                    (base[y] - base[y - 1]) * large[large.idx(n / x / y)];
            }
    }

    for (auto &p : ps) {
        if (p > SQ6)
            break;
        T buf[65];
        rep(e, 0, 65) buf[e] = pe(p, e);
        rrep(i, 1, base.sz) {
            ll x = base.val(i) / p;
            for (int e = 1;; e++) {
                base[i] += base[base.idx(x)] * buf[e];
                x /= p;
                if (x == 0)
                    break;
            }
        }
    }

    return base;
}

/**
 * @brief Multiplicative Sum $O(n^{2/3}(\log n)^{-1})$
 * @ref
 * https://scrapbox.io/nachia-cp/%E4%B9%97%E6%B3%95%E7%9A%84%E9%96%A2%E6%95%B0%E7%B4%AF%E7%A9%8D%E5%92%8C-%E4%B8%AD%E5%9B%BD%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%83%86%E3%82%A3%E3%81%AE%E6%96%B9%E6%B3%95
 */
#line 2 "Math/sieve.hpp"

template <int L = 101010101> vector<int> sieve(int N) {
    bitset<L> isp;
    int n, sq = ceil(sqrt(N));
    for (int z = 1; z <= 5; z += 4) {
        for (int y = z; y <= sq; y += 6) {
            for (int x = 1; x <= sq and (n = 4 * x * x + y * y) <= N; ++x) {
                isp[n].flip();
            }
            for (int x = y + 1; x <= sq and (n = 3 * x * x - y * y) <= N;
                 x += 2) {
                isp[n].flip();
            }
        }
    }
    for (int z = 2; z <= 4; z += 2) {
        for (int y = z; y <= sq; y += 6) {
            for (int x = 1; x <= sq and (n = 3 * x * x + y * y) <= N; x += 2) {
                isp[n].flip();
            }
            for (int x = y + 1; x <= sq and (n = 3 * x * x - y * y) <= N;
                 x += 2) {
                isp[n].flip();
            }
        }
    }
    for (int y = 3; y <= sq; y += 6) {
        for (int z = 1; z <= 2; ++z) {
            for (int x = z; x <= sq and (n = 4 * x * x + y * y) <= N; x += 3) {
                isp[n].flip();
            }
        }
    }
    for (int n = 5; n <= sq; ++n)
        if (isp[n]) {
            for (int k = n * n; k <= N; k += n * n) {
                isp[k] = false;
            }
        }
    isp[2] = isp[3] = true;

    vector<int> ret;
    for (int i = 2; i <= N; i++)
        if (isp[i]) {
            ret.push_back(i);
        }
    return ret;
}

/**
 * @brief Prime Sieve
 */
#line 3 "Math/multiplicative2.hpp"

template <typename T> struct Dir {
    ll n;
    int SQ, sz;
    vector<T> dat;
    Dir() {}
    Dir(ll n) : n(n), SQ(sqrtl(n)), sz(SQ + n / (SQ + 1) + 1), dat(sz) {}
    T &operator[](int i) {
        return dat[i];
    }
    void pref() {
        rep(i, 0, sz - 1) dat[i + 1] += dat[i];
    }
    void diff() {
        rrep(i, 0, sz - 1) dat[i + 1] -= dat[i];
    }
    int idx(ll x) const {
        return (x <= SQ ? x : sz - n / x);
    }
    ll val(int id) const {
        return (id <= SQ ? id : n / (sz - id));
    }
};

template <typename T> Dir<T> mult(ll n, Dir<T> &a, Dir<T> &b) {
    int SQ = sqrtl(n);
    Dir<T> c(n);
    int thre = a.idx(max<int>(1, pow(n, 2. / 3)));
    auto get = [&](Dir<T> &A, Dir<T> &B) -> vector<pair<int, T>> {
        vector<pair<int, T>> ret;
        rep(i, 1, SQ + 1) if (A[i - 1] != A[i]) {
            T x = A[i] - A[i - 1];
            ret.push_back({i, x});
            rrep(j, thre + 1, c.sz) {
                ll k = c.val(j);
                int to = B.idx(k / i);
                if (to < i)
                    break;
                c[j] += x * B[to];
            }
        }
        rep(i, SQ + 1, thre + 1) {
            if (A[i - 1] != A[i]) {
                T x = A[i] - A[i - 1];
                ret.push_back({A.val(i), x});
            }
        }
        return ret;
    };
    auto posA = get(a, b);
    auto posB = get(b, a);
    for (auto &[v, x] : posA) {
        for (auto &[w, y] : posB) {
            int to = c.idx(ll(v) * w);
            if (to > thre)
                break;
            c[c.idx(v * w)] += x * y;
        }
    }
    rep(i, 1, thre + 1) {
        c[i] += c[i - 1];
    }

    rrep(i, thre + 1, c.sz) {
        ll x = c.val(i);
        int j = sqrtl(x);
        c[i] -= a[j] * b[j];
    }

    return c;
}

template <typename T, T (*F)(ll)> Dir<T> getLarge(ll n) {
    Dir<T> base(n);
    int SQ = sqrtl(n);
    auto ps = sieve(SQ);
    vector<T> small(SQ + 10);
    rep(x, 1, SQ + 10) small[x] = F(x);
    rrep(i, 1, SQ + 10) small[i] -= small[i - 1];
    Dir<T> den(n), lg(n);

    int SQ6 = max<int>(1, pow(n, 1. / 6));
    for (auto &p : ps)
        if (SQ6 < p) {
            T f_p = small[p];
            T X[10] = {}, base[10] = {};
            rep(i, 1, 10) {
                base[i] = POW<T>(f_p, i);
            }
            rep(i, 1, 10) {
                T tmp = base[i] * i;
                rep(j, 1, i + 1) tmp -= base[j] * X[i - j];
                X[i] = tmp;
            }
            rep(i, 1, 10) X[i] /= i;

            for (ll x = 1, i = 0;; x *= p, i++) {
                lg[den.idx(x)] += X[i];
                if (x > n / p)
                    break;
            }
        }
    lg.pref();

    // exp
    {
        Dir<T> add(n);
        rep(i, 1, add.sz) add[i] = den[i] = 1;
        rep(e, 1, 5 + 1) {
            add = mult(n, add, lg);
            rep(i, 1, add.sz) den[i] += add[i] * Fact<T>(e, 1);
        }
    }

    for (auto &p : ps)
        if (p <= SQ6) {
            T f_p = small[p];
            rep(i, 1, den.sz) {
                ll x = den.val(i);
                den[i] += den[den.idx(x / p)] * f_p;
            }
        }

    Dir<T> ret(n);
    rrep(i, 1, SQ + 1) if (n / i > SQ) {
        int id = den.idx(n / i);
        T tmp = F(n / i) - den[id];
        for (int j = 2; i * j <= SQ; j++)
            tmp -= small[j] * ret[ret.idx(n / i / j)];
        ret[id] = tmp;
    }

    ret.diff();
    return ret;
}

template <typename T, T (*pe)(int p, int e)>
Dir<T> MultiplicativeSum(ll n, Dir<T> &large) {
    Dir<T> base(n), lg(n);
    int SQ = sqrtl(n);
    auto ps = sieve(SQ);

    int SQ6 = max<int>(1, pow(n, 1. / 6));
    for (auto &p : ps) {
        if (p <= SQ6)
            continue;
        T X[10] = {}, base[10] = {};
        rep(i, 1, 10) {
            base[i] = pe(p, i);
        }
        rep(i, 1, 10) {
            T tmp = base[i] * i;
            rep(j, 1, i + 1) tmp -= base[j] * X[i - j];
            X[i] = tmp;
        }
        rep(i, 1, 10) X[i] /= i;
        for (ll x = 1, i = 0;; x *= p, i++) {
            lg[lg.idx(x)] += X[i];
            if (x > n / p)
                break;
        }
    }
    lg.pref();

    // exp
    {
        Dir<T> add(n);
        rep(i, 1, add.sz) add[i] = base[i] = 1;
        rep(e, 1, 5 + 1) {
            add = mult(n, add, lg);
            rep(i, 1, add.sz) base[i] += add[i] * Fact<T>(e, 1);
        }
    }

    rrep(x, 1, SQ + 1) {
        int i = base.idx(n / x);
        for (int y = 1; x * y <= SQ; y++)
            if (base[y - 1] != base[y]) {
                base[i] +=
                    (base[y] - base[y - 1]) * large[large.idx(n / x / y)];
            }
    }

    for (auto &p : ps) {
        if (p > SQ6)
            break;
        T buf[65];
        rep(e, 0, 65) buf[e] = pe(p, e);
        rrep(i, 1, base.sz) {
            ll x = base.val(i) / p;
            for (int e = 1;; e++) {
                base[i] += base[base.idx(x)] * buf[e];
                x /= p;
                if (x == 0)
                    break;
            }
        }
    }

    return base;
}

/**
 * @brief Multiplicative Sum $O(n^{2/3}(\log n)^{-1})$
 * @ref
 * https://scrapbox.io/nachia-cp/%E4%B9%97%E6%B3%95%E7%9A%84%E9%96%A2%E6%95%B0%E7%B4%AF%E7%A9%8D%E5%92%8C-%E4%B8%AD%E5%9B%BD%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%83%86%E3%82%A3%E3%81%AE%E6%96%B9%E6%B3%95
 */
Back to top page