标签: 莫比乌斯反演

  • noi.ac180 divisors

    $$ \sum_{1\le i\le n}{\sum_{d|i}{gcd\left( d,\frac{i}{d} \right)}} \\ =\sum_{1\le x\le n}{x\sum_{1\le i\le n}{\sum_{d|i}{\left[ gcd\left( d,\frac{i}{d} \right) =x \right]}}} \\ =\sum_{1\le x\le n}{x\sum_{1\le i\le \lfloor \frac{n}{x^2} \rfloor}{\sum_{d|i}{\left[ gcd\left( d,\frac{i}{d} \right) =1 \right]}}} \\ =\sum_{1\le x\le n}{x\sum_{1\le i\le \lfloor \frac{n}{x^2} \rfloor}{\sum_{d|i}{\sum_{k|d,k|\frac{i}{d}}{\mu \left( k \right)}}}} \\ =\sum_{1\le x\le n}{x\sum_{1\le k\le \lfloor \frac{n}{x^2} \rfloor}{\mu \left( k \right)}\sum_{1\le i\le \lfloor \frac{n}{k^2x^2} \rfloor}{\sum_{d|i}{1}}} \\ \text{设}f\left( x \right) =\sum_{1\le i\le x}{\sum_{d|i}{1}}=\sum_{1\le i\le x}{\lfloor \frac{x}{i} \rfloor} \\ \text{则有}\sum_{1\le x\le n}{x\sum_{1\le k\le \lfloor \frac{n}{x^2} \rfloor}{\mu \left( k \right) f\left( \lfloor \frac{n}{k^2x^2} \rfloor \right)}} \\ \text{令}T=kx,\text{则有} \\ \sum_{\,\,1\le T\le n}{f\left( \lfloor \frac{n}{T^2} \rfloor \right) \sum_{k|T}{\mu \left( k \right) \frac{T}{k}}}=\sum_{1\le T\le n}{f\left( \lfloor \frac{n}{T^2} \rfloor \right) \varphi \left( T \right)} \\ \text{由于}T^2\le n,\text{故}T\le \sqrt{n} \\ \text{则有}\sum_{1\le T\le \sqrt{n}}{f\left( \lfloor \frac{n}{T^2} \rfloor \right) \varphi \left( T \right)} \\ \text{复杂度}O\left( \sum_{1\le i\le \sqrt{n}}{\sqrt{\frac{n}{i^2}}} \right) =O\left( \sqrt{n}\log n \right) \\ \\ $$

    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <vector>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    const int_t LARGE = 5e6;
    bool isPrime[LARGE + 1];
    std::vector<int_t> primes;
    int_t factor[LARGE + 1], phi[LARGE + 1];
    int_t f(int_t n) {
        int_t i = 1, result = 0;
        // int_t px = n;
        while (i * i <= n) {
            result += (n / i);
            // px--;
            i++;
        }
        int_t k = n / i;
        while (i <= n) {
            // int_t t
            int_t next = n / k;
            result += k * (next - i + 1);
            i = next + 1;
            k--;
        }
        return result;
    }
    int main() {
        int_t n;
        cin >> n;
        int_t sqrt = ::sqrt(n) + 1;
        memset(isPrime, 1, sizeof(isPrime));
        phi[1] = 1;
        for (int_t i = 2; i <= sqrt; i++) {
            if (isPrime[i]) {
                factor[i] = i;
                primes.push_back(i);
            }
            for (int_t x : primes) {
                if (i * x > sqrt) break;
                isPrime[i * x] = false;
                factor[i * x] = x;
                // factor[i * x] = x;
                if (i % x == 0) break;
            }
        }
    #ifdef DEBUG
        for (int_t x : primes) cout << x << endl;
    #endif
        phi[1] = 1;
        for (int_t i = 2; i <= sqrt; i++) {
            int_t p = factor[i];
            if (i / p % p == 0)
                phi[i] = phi[i / p] * p;
            else
                phi[i] = phi[i / p] * (p - 1);
        }
        int_t result = 0;
        for (int_t i = 1; i * i <= n; i++) {
            result += f(n / (i * i)) * phi[i];
    #ifdef DEBUG
    
            cout << "phi " << i << " = " << phi[i] << endl;
    
    #endif
        }
        cout << result << endl;
        return 0;
    }

     

  • BZOJ2627 JZPKIL

    emm不管了…BZOJ算的是总时限我才能A..

    一开始用的拉格朗日插值,然后发现太慢,于是换成伯努利数..

    $$ \sum_{1\le i\le n}{\text{gcd}\left( i,n \right) ^x\text{lcm}\left( i,n \right) ^y} \\ =n^y\sum_{1\le i\le n}{\text{gcd}\left( i,n \right) ^{x-y}i^y} \\ =n^y\sum_{d|n}{d^{x-y}\sum_{1\le i\le n}{i^y\left[ \text{gcd}\left( i,n \right) =d \right]}} \\ =n^y\sum_{d|n}{d^x\sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{i^y\left[ \text{gcd}\left( i,\frac{n}{d} \right) =1 \right]}} \\ =n^y\sum_{d|n}{d^x\sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{i^y\sum_{k|\text{gcd}\left( i,\frac{n}{d} \right)}{\mu \left( k \right)}}} \\ =n^y\sum_{d|n}{d^x\sum_{1\le k\le \lfloor \frac{n}{d} \rfloor}{\mu \left( k \right) \sum_{1\le i\le \frac{n}{d}}{i^y\left[ k|i \right] \left[ k|\frac{n}{d} \right]}}} \\ =n^y\sum_{d|n}{d^x\sum_{k|\frac{n}{d}}{\mu \left( k \right) \sum_{k|i,i\le \frac{n}{d}}{i^y}}} \\ =n^y\sum_{d|n}{d^x\sum_{k|\frac{n}{d}}{\mu \left( k \right) k^y\sum_{1\le i\le \frac{n}{kd}}{i^y}}} \\ \text{设}S\left( n \right) =\sum_{1\le i\le n}{i^y} \\ \text{原式}=n^y\sum_{d|n}{\left( \frac{n}{d} \right) ^x\sum_{k|d}{\mu \left( k \right) k^yS\left( \frac{d}{k} \right)}} \\ =n^y\sum_{k|n}{\mu \left( k \right) k^y\sum_{k|d,d|n}{S\left( \frac{ik}{k} \right) \left( \frac{n}{ik} \right) ^x}} \\ =n^y\sum_{k|n}{\mu \left( k \right) k^y\sum_{1\le i\le \frac{n}{k},i|\frac{n}{k}}{S\left( i \right) \left( \frac{n}{ik} \right) ^x}} \\ =n^y\sum_{k|n}{\mu \left( k \right) k^y\sum_{i|\frac{n}{k}}{S\left( i \right) \left( \frac{n}{ik} \right) ^x}} \\ =n^y\sum_{k|n}{\mu \left( \frac{n}{k} \right) \left( \frac{n}{k} \right) ^y\sum_{d|k}{S\left( d \right) \left( \frac{k}{d} \right) ^x}} \\ =n^y\sum_{d|n}{S\left( d \right) \sum_{i|\frac{n}{d}}{\mu \left( \frac{n}{id} \right) \left( \frac{n}{id} \right) ^y}}\left( i \right) ^x \\ =n^y\sum_{d|n}{S\left( d \right) \left( \frac{n}{d} \right) ^x\sum_{i|\frac{n}{d}}{\mu \left( i \right) \left( \frac{1}{i} \right) ^{x-y}}} \\ \text{此时如果}x=y,\text{则原式}=n^y\sum_{d|n}{S\left( d \right) \left( \frac{n}{d} \right) ^x\left[ n=d \right] =n^yS\left( n \right)} \\ \text{否则原式}=n^y\sum_{d|n}{S\left( d \right) \left( \frac{n}{d} \right) ^x\prod_{p\,\,| \frac{n}{d}\,\,and\,\,p\,\,is\,\,a\,\,prime}{\left( 1-\left( \frac{1}{p} \right) ^{x-y} \right)}}\left( x\ne y \right) \\ \text{设}f\left( n \right) =\prod_{p\,\,| n\,\,and\,\,p\,\,is\,\,a\,\,prime}{\left( 1-\left( \frac{1}{p} \right) ^{x-y} \right)},f\text{函数可以在枚举约数时顺便处理出来} \\ \\ \text{又因为}S\left( n \right) =\sum_{1\le i\le n}{i^y}=\frac{1}{y+1}\sum_{0\le i\le y}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_in^{y+1-i}} \\ =\frac{1}{y+1}\sum_{-y\le -i\le 0}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_in^{y+1-i}} \\ =\frac{1}{y+1}\sum_{0\le y-i\le y}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_in^{y+1-i}} \\ =\frac{1}{y+1}\sum_{1\le y-i+1\le y+1}{\left( \begin{array}{c} y+1\\ y-i+1\\ \end{array} \right) B_{y-i+1}n^{y+1-\left( y-i+1 \right)}} \\ =\frac{1}{y+1}\sum_{1\le i\le y+1}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_{y-i+1}n^i} \\ \text{故预处理出伯努利数后,可以在}O\left( n \right) \text{的时间内计算出多项式}S\left( n \right) \\ \text{由于}\sum_{0\le i\le m}{\left( \begin{array}{c} m+1\\ i\\ \end{array} \right) B_i=\left[ m=0 \right]} \\ \text{故}B_0=\text{1,对于}i>0 \\ \left( \begin{array}{c} m+1\\ m\\ \end{array} \right) B_m+\sum_{0\le i<m}{\left( \begin{array}{c} m+1\\ i\\ \end{array} \right) B_i=0} \\ B_m=-\frac{\sum_{0\le i<m}{\left( \begin{array}{c} m+1\\ i\\ \end{array} \right) B_i}}{m+1} \\ $$

    #include <inttypes.h>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <random>
    #include <unordered_map>
    #include <utility>
    #include <vector>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::cout;
    using std::endl;
    
    using pair_t = std::pair<int_t, int_t>;
    
    const int_t mod = 1e9 + 7;
    const int_t LARGE = 3003;
    int_t B[LARGE + 10], fact[LARGE + 10], factInv[LARGE + 10];
    std::mt19937 gen;
    int_t mul(int_t a, int_t b, int_t mod) { return (__int128_t)a * b % mod; }
    int_t C(int_t n, int_t m) {
        return fact[n] * factInv[m] % mod * factInv[n - m] % mod;
    }
    int_t power(int_t base, int_t index, int_t mod) {
        int_t result = 1;
        if (index < 0) {
            index += mod - 1;
        }
        while (index) {
            if (index & 1) result = mul(result, base, mod);
            index >>= 1;
            base = mul(base, base, mod);
        }
        return result;
    }
    bool isPrime(int_t n) {
        if (n <= 1) return false;
        if (n == 2 || n == 3) return true;
        int_t s = 0, t = n - 1;
        while (t % 2 == 0) {
            t /= 2;
            s++;
        }
        std::uniform_int_distribution<int_t> rand_int(2, n - 1);
        for (int_t _i = 1; _i <= 3; _i++) {
            int_t a = rand_int(gen);
            int_t prev = power(a, t, n);
            for (int_t i = 1; i <= s; i++) {
                int_t curr = mul(prev, prev, n);
                if (curr == 1 && prev != 1 && prev != n - 1) return false;
                prev = curr;
            }
            if (prev != 1) return false;
        }
        return true;
    }
    int_t gcd(int_t a, int_t b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
    int_t getFactor(int_t n, int_t c) {
        const auto f = [=](int_t x) { return (mul(x, x, n) + c) % n; };
        std::uniform_int_distribution<int_t> rand_int(2, n - 1);
        int_t x = rand_int(gen), y = rand_int(gen);
        int_t i = 0, k = 2;
        int_t prod = 1, factor = 1;
        while (true) {
            i++;
            x = f(x);
            prod = mul(prod, std::abs(x - y), n);
            if (i % 256 == 0) {
                factor = gcd(prod, n);
                if (factor > 1) return factor;
            }
            if (x == y) return n;
            if (i == k) {
                i = 0;
                k *= 2;
                y = x;
                factor = std::max(factor, gcd(n, prod));
                if (factor > 1) return factor;
                prod = 1;
                factor = 1;
            }
        }
    }
    template <class CT>
    void pollardRho(int_t n, CT& output) {
        if (isPrime(n)) {
            output[n] += 1;
            return;
        }
        int_t seed = gen();
        int_t factor = n;
        while (factor == n) {
            factor = getFactor(factor, seed--);
            if (seed == 0) seed = gen();
        }
        pollardRho(factor, output);
        pollardRho(n / factor, output);
    }
    void getPoly(int_t y, int_t* output) {
        int_t prod = power(y + 1, mod - 2, mod);
        output[0] = 0;
        for (int_t i = 1; i <= y + 1; i++)
            output[i] = C(y + 1, i) * B[y - i + 1] % mod * prod % mod;
    }
    void DFS(int_t n, const std::unordered_map<int_t, int_t>& primeVals,
             std::vector<pair_t>& counts, int_t prod, int_t funcProd,
             std::vector<pair_t>& output) {
        if (n >= counts.size()) {
    #ifdef DEBUG
            cout << "divisor " << prod << " func " << funcProd << endl;
    #endif
            output.push_back(pair_t(prod, funcProd));
            return;
        }
        //²»¿¼ÂÇÕâ¸öÒòÊý
    #ifdef DEBUG
        cout << "setting " << counts[n].first << " time to " << 0
             << " and prev = " << 1 << "curr n = " << n << endl;
    #endif
        DFS(n + 1, primeVals, counts, prod, funcProd, output);
        int_t prev = counts[n].first;
        for (int_t i = 1; i <= counts[n].second; i++) {
    #ifdef DEBUG
            cout << "setting " << counts[n].first << " time to " << i
                 << " and prev = " << prev << "curr n = " << n << endl;
    #endif
            DFS(n + 1, primeVals, counts, prod * prev,
                funcProd * primeVals.at(counts[n].first) % mod, output);
            prev = prev * counts[n].first;
        }
    #ifdef DEBUG
        cout << "backing " << endl;
    #endif
    }
    int_t process(int_t n, int_t x, int_t y) {
        static int_t poly[LARGE + 10];
        memset(poly, 0, sizeof(poly));
        getPoly(y, poly);
        const auto sub = [&](int_t x) {
            //ÌØÅÐy=0
            if (y == 0) return x;
            int_t result = 0;
            int_t pow = 1;
            x %= mod;
            x += 1;
            for (int_t i = 1; i <= y + 1; i++) {
                result = (result + poly[i] * pow % mod) % mod;
                pow = pow * x % mod;
            }
    #ifdef DEBUG
            cout << "sub " << x << " = " << result << endl;
    #endif
            return result;
        };
    #ifdef DEBUG
        while (true) {
            int_t x;
            cin >> x;
            cout << sub(x) << endl;
        }
    #endif
        if (x == y) {
            return power(n, y, mod) * sub(n) % mod;
        }
        std::unordered_map<int_t, int_t> output;
        pollardRho<std::unordered_map<int_t, int_t>>(n, output);
    #ifdef DEBUG
        for (const auto& kvp : output)
            cout << kvp.first << " = " << kvp.second << endl;
    #endif
        std::unordered_map<int_t, int_t> primeVals;
        std::vector<pair_t> counts;
        std::vector<pair_t> divisors;
        std::unordered_map<int_t, int_t> func;
        for (const auto& kvp : output) {
            primeVals[kvp.first] =
                (1 - power(kvp.first, (y - x + mod - 1) % (mod - 1), mod) + mod) %
                mod;
            counts.push_back(kvp);
        }
        DFS(0, primeVals, counts, 1, 1, divisors);
        for (const auto& kvp : divisors) {
            func[kvp.first] = kvp.second;
        }
        int_t result = 0;
        for (const auto& kvp : divisors) {
            int_t d = kvp.first;
            result = (result + sub(d) * power(n, x, mod) % mod *
                                   power(d, mod - 1 - x, mod) % mod * func[n / d] %
                                   mod) %
                     mod;
    #ifdef DEBUG
            cout << "divisor " << d << " count "
                 << sub(d) * power(n, x, mod) % mod * power(d, mod - 1 - x, mod) %
                        mod * func[n / d] % mod
                 << endl;
    #endif
        }
        result = result * power(n, y, mod) % mod;
        return result;
    }
    
    int main() {
        fact[0] = fact[1] = factInv[0] = factInv[1] = 1;
        for (int_t i = 2; i <= LARGE + 2; i++) {
            fact[i] = fact[i - 1] * i % mod;
            factInv[i] = (mod - mod / i) * factInv[mod % i] % mod;
        }
        for (int_t i = 2; i <= LARGE + 2; i++)
            factInv[i] = factInv[i - 1] * factInv[i] % mod;
        B[0] = 1;
        for (int_t i = 1; i <= LARGE + 2; i++) {
            int_t sum = 0;
            for (int_t j = 0; j < i; j++)
                sum = (sum + C(i + 1, j) * B[j] % mod) % mod;
            B[i] = (mod - sum) * power(i + 1, mod - 2, mod) % mod;
    #ifdef DEBUG
            if (i <= 10) cout << "B " << i << " = " << B[i] << endl;
    #endif
        }
        gen.seed(std::random_device()());
        int_t T;
        cin >> T;
        while (T--) {
            int_t n, x, y;
            cin >> n >> x >> y;
            cout << process(n, x, y) << endl;
        }
        return 0;
    }

     

  • CF1139D Steps to One

    $$ E\left( X \right) ,X\text{长度} \\ E\left( X \right) =\sum_{i\ge 1}{P\left( X\ge i \right)},i\text{是长度} \\ =1+\sum_{i\ge 2}{\frac{m^{i-1}-\sum_{1\le j\le m}{\mu \left( j \right) \lfloor \frac{m}{j} \rfloor ^{i-1}}}{m^{i-1}}}\left( \text{枚举长度}i\text{,钦定长度小于}i\text{的全都不互质} \right) \\ 1+\sum_{i\ge 1}{\frac{m^i-\sum_{1\le j\le m}{\mu \left( j \right) \lfloor \frac{m}{j} \rfloor ^i}}{m^i}} \\ 1+\sum_{i\ge 1}{\frac{m^i-m^i-\sum_{2\le j\le m}{\mu \left( j \right) \lfloor \frac{m}{j} \rfloor ^i}}{m^i}} \\ =1-\sum_{1\ge 1}{\frac{\sum_{2\le j\le m}{\mu \left( j \right) \lfloor \frac{m}{j} \rfloor ^i}}{m^i}} \\ 1-\sum_{2\le j\le m}{\mu \left( j \right) \sum_{1\ge 1}{\left( \frac{\lfloor \frac{m}{j} \rfloor}{m} \right) ^i}} \\ =1-\sum_{2\le j\le m}{\mu \left( j \right)}\frac{\lfloor \frac{m}{j} \rfloor}{m}\underset{n\rightarrow \infty}{\lim}\frac{1-\left( \frac{\lfloor \frac{m}{j} \rfloor}{m} \right) ^n}{1-\frac{\lfloor \frac{m}{j} \rfloor}{m}} \\ =1-\sum_{2\le j\le m}{\mu \left( j \right)}\frac{\lfloor \frac{m}{j} \rfloor}{m}\frac{1}{1-\frac{\lfloor \frac{m}{j} \rfloor}{m}} \\ =1-\sum_{2\le j\le m}{\mu \left( j \right)}\frac{\lfloor \frac{m}{j} \rfloor}{m-\lfloor \frac{m}{j} \rfloor} \\ $$

    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t mod = 1e9 + 7;
    const int_t LARGE = 1e5;
    int_t inv[LARGE + 1];
    int_t m;
    int_t mu[LARGE + 1];
    int_t factor[LARGE + 1];
    bool isPrime[LARGE + 1];
    
    int main() {
        memset(isPrime, 1, sizeof(isPrime));
        cin >> m;
        inv[1] = 1;
        for (int_t i = 2; i <= m; i++)
            inv[i] = (mod - mod / i) * inv[mod % i] % mod;
        for (int_t i = 2; i <= m; i++)
            if (isPrime[i]) {
                for (int_t j = i * i; j <= m; j += i) {
                    factor[j] = i;
                    isPrime[j] = false;
                }
                factor[i] = i;
            }
        mu[1] = 1;
        for (int_t i = 2; i <= m; i++) {
            int_t p = factor[i];
            if (i / p % p == 0)
                mu[i] = 0;
            else
                mu[i] = mu[i / p] * -1;
        }
        int_t result = 1;
        for (int_t i = 2; i <= m; i++) {
            int_t x = m / i;
            result = (result - mu[i] * x % mod * inv[m - x] % mod + mod) % mod;
        }
        cout << result << endl;
        return 0;
    }

     

  • UOJ62 怎样跑得更快

    $$ \sum_{1\le j\le n}{gcd\left( i,j \right) ^clcm\left( i,j \right) ^d\times x_j=b_i} \\ \sum_{1\le j\le n}{gcd\left( i,j \right) ^{c-d}j^dx_j=\frac{b_i}{i^d}} \\ \text{设}f\left( n \right) =n^{c-d}=\sum_{k|n}{g\left( k \right)},\text{则有}g\left( n \right) =\sum_{k|n}{\mu \left( \frac{n}{k} \right) k^{c-d}} \\ \sum_{1\le j\le n}{\sum_{k|gcd\left( i,j \right)}{g\left( k \right)}j^dx_j=\frac{b_i}{i^d}} \\ \sum_{1\le j\le n}{\begin{array}{c} \sum_{k|i\,\,and\,\,k|j}{g\left( k \right) j^dx_j=\frac{b_i}{i^d}}\\ \end{array}} \\ \sum_{k|i}{g\left( k \right) \sum_{k|j,j\le n}{j^dx_j}}=\frac{b_i}{i^d} \\ \text{令}h\left( k \right) =\sum_{k|j,j\le n}{j^dx_j},\text{同时又}i^dx_i=\sum_{i|k,k\le n}{\mu \left( \frac{k}{i} \right) h\left( k \right)},x_i=\frac{\sum_{i|k,k\le n}{\mu \left( \frac{k}{i} \right) h\left( k \right)}}{i^d} \\ \text{故}\sum_{k|i}{g\left( k \right) h\left( k \right) =\frac{b_i}{i^d}} \\ g\left( i \right) h\left( i \right) =\sum_{k|i}{\mu \left( \frac{i}{k} \right) \frac{b_k}{k^d}=w\left( i \right)},\text{如果存在}g\left( i \right) =\text{0且}w\left( i \right) =\text{0,则}h\left( i \right) \text{可取任意值}. \\ \text{如果}g\left( n \right) \text{为0但是}\sum_{k|i}{\mu \left( \frac{i}{k} \right) \frac{b_k}{k^d}}=\text{0不为0,无解。} \\ \\ h\left( i \right) =\frac{\sum_{k|i}{\mu \left( \frac{i}{k} \right) \frac{b_k}{k^d}}}{\sum_{u|i}{\mu \left( \frac{i}{u} \right) u^{c-d}}} \\ \text{故}x_i=\frac{\sum_{i|k,k\le n}{\mu \left( \frac{k}{i} \right) h\left( k \right)}}{i^d} \\ g\left( n \right) =\sum_{k|n}{\mu \left( \frac{n}{k} \right) k^{c-d}} \\ w\left( n \right) =\sum_{k|n}{\mu \left( \frac{n}{k} \right) \frac{b_k}{k^d}} \\ h\left( n \right) =\frac{w\left( n \right)}{g\left( n \right)} \\ $$

    #include <cstring>
    #include <iostream>
    using std::cin;
    using std::cout;
    using std::endl;
    using int_t = long long int;
    
    const int_t LARGE = 1e5;
    const int_t mod = 998244353;
    int_t power(int_t base, int_t index);
    
    int_t mu[LARGE + 1];
    bool isPrime[LARGE + 1];
    int_t factor[LARGE + 1];
    int_t g[LARGE + 1];
    int_t w[LARGE + 1];
    int_t h[LARGE + 1];
    int_t n, c, d, q;
    void process() {
        static int_t b[LARGE + 1];
        bool fail = false;
        for (int_t i = 1; i <= n; i++) cin >> b[i];
        std::fill(w + 1, w + 1 + n, 0);
        std::fill(h + 1, h + 1 + n, 0);
        for (int_t i = 1; i <= n; i++) {
            int_t f = b[i] * power(i, -d) % mod;
            for (int_t j = 1; j * i <= n; j++) {
                w[j * i] = (w[j * i] + f * mu[j] + mod) % mod;
            }
        }
        for (int_t i = 1; i <= n; i++) {
            if (g[i] == 0) {
                if (w[i] != 0) {
                    fail = true;
                    break;
                } else {
                    h[i] = 0;
                }
            } else {
                h[i] = w[i] * power(g[i], -1) % mod;
            }
        }
        if (fail) {
            cout << -1 << endl;
            return;
        }
        for (int_t i = 1; i <= n; i++) {
            int_t curr = 0;
            for (int_t j = 1; j * i <= n; j++) {
                curr = (curr + mu[j] * h[j * i] % mod + mod) % mod;
            }
            curr = curr * power(i, -d) % mod;
            cout << curr << " ";
        }
        cout << endl;
    }
    int main() {
        cin >> n >> c >> d >> q;
        memset(isPrime, 1, sizeof(isPrime));
        for (int_t i = 2; i <= n; i++) {
            if (isPrime[i]) {
                for (int_t j = i * i; j <= n; j += i) {
                    isPrime[j] = false;
                    factor[j] = i;
                }
                factor[i] = i;
            }
        }
        mu[1] = 1;
        for (int_t i = 2; i <= n; i++) {
            int_t factor = ::factor[i];
            if (i / factor % factor == 0)
                mu[i] = 0;
            else {
                mu[i] = mu[i / factor] * -1;
            }
        }
        for (int_t i = 1; i <= n; i++) {
            int_t f = power(i, c - d);
            for (int_t j = 1; j * i <= n; j++) {
                g[j * i] = (g[j * i] + f * mu[j] + mod) % mod;
            }
        }
        while (q--) {
            process();
        }
        return 0;
    }
    
    int_t power(int_t base, int_t index) {
        int_t result = 1;
        const auto phi = mod - 1;
        index = (index % phi + phi) % phi;
        base = (base % mod + mod) % mod;
        while (index) {
            if (index & 1) result = result * base % mod;
            index >>= 1;
            base = base * base % mod;
        }
        return result;
    }

     

  • NOI2016 循环之美

    $$ \text{设循环节长度为}l,,\text{如果有}\frac{x}{y}\text{为纯循环小数,则有} \\ \frac{x}{y}\,\,mod\,\,\text{1 }=\frac{x}{y}k^l\,\,mod\,\,1 \\ \text{即} \\ \frac{x}{y}-\lfloor \frac{x}{y} \rfloor =\frac{xk^l}{y}-\lfloor \frac{xk^l}{y} \rfloor \\ x-y\lfloor \frac{x}{y} \rfloor =xk^l-y\lfloor \frac{xk^l}{y} \rfloor \\ \text{由于}x\,\,mod\,\,y=x-y\lfloor \frac{x}{y} \rfloor \\ \text{故}x-y\lfloor \frac{x}{y} \rfloor =xk^l-y\lfloor \frac{xk^l}{y} \rfloor \text{等价于} \\ x=xk^l\left( mod\,\,y \right) \\ \text{由于}\frac{x}{y}\text{为最简分数,故}x\text{与}y\text{互质,所以} \\ 1=k^l\left( mod\,\,y \right) \\ \text{当且仅当}k\text{与}y\text{互质的时候,存在}l=c\varphi \left( y \right) \text{使得}1=k^l\left( mod\,\,y \right) \text{成立,故答案等价于统计} \\ \sum_{1\le i\le n}{\sum_{1\le j\le m}{\left[ gcd\left( i,j \right) =1 \right] \left[ gcd\left( j,k \right) =1 \right]}} \\ \text{设}f\left( n,m,k \right) =\sum_{1\le i\le n}{\sum_{1\le j\le m}{\left[ gcd\left( i,j \right) ==1 \right] \left[ gcd\left( j,k \right) ==1 \right]}} \\ f\left( n,m,k \right) =\sum_{1\le i\le n}{\sum_{1\le j\le m}{\left[ gcd\left( i,j \right) =1 \right] \sum_{d|gcd\left( j,k \right)}{\mu \left( d \right)}}} \\ =\sum_{1\le i\le n}{\sum_{1\le jd\le m}{\left[ gcd\left( i,jd \right) =1 \right] \sum_{d|gcd\left( jd,k \right)}{\mu \left( d \right)}}} \\ =\sum_{1\le i\le n}{\sum_{1\le jd\le m}{\left[ gcd\left( i,jd \right) =1 \right] \sum_{d|k}{\mu \left( d \right)}}} \\ =\sum_{d|k}{\mu \left( d \right) \sum_{1\le i\le n}{\sum_{1\le j\le \lfloor \frac{m}{d} \rfloor}{\left[ gcd\left( i,jd \right) =1 \right]}}} \\ =\sum_{d|k}{\mu \left( d \right) \sum_{1\le i\le n}{\sum_{1\le j\le \lfloor \frac{m}{d} \rfloor}{\left[ gcd\left( i,j \right) =1 \right] \left[ gcd\left( i,d \right) =1 \right]}}} \\ =\sum_{d|k}{\mu \left( d \right) \sum_{1\le i\le \lfloor \frac{m}{d} \rfloor}{\sum_{1\le j\le n}{\left[ gcd\left( i,j \right) =1 \right] \left[ gcd\left( j,d \right) =1 \right]}}} \\ =\sum_{d|k\,\,and\,\,\mu \left( d \right) \ne 0}{\mu \left( d \right) f\left( \lfloor \frac{m}{d} \rfloor ,n,d \right)}\left( \text{直接过滤掉}\mu \left( d \right) \text{为0的}d,\text{加快时间} \right) \\ \text{边界条件}f\left( n,m,k \right) =0\left( n=\text{0或}m=0 \right) \\ f\left( n,m,1 \right) =\sum_{1\le i\le n}{\sum_{1\le j\le m}{\left[ gcd\left( i,j \right) =1 \right]}}=\sum_{1\le k\le \min \left( n,m \right)}{\mu \left( k \right) \lfloor \frac{n}{k} \rfloor \lfloor \frac{m}{k} \rfloor},\text{可以通过杜教筛快速求出。} \\ \text{复杂度瞎猜一顿是}O\left( kf\left( k \right) \log n\log m+n^{\frac{2}{3}} \right) ,\text{其中}f\left( k \right) \text{是}k\text{的约数中莫比乌斯函数值不为0的约数个数} $$

    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <ext/pb_ds/hash_policy.hpp>
    #include <iostream>
    #include <unordered_map>
    #include <vector>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    const int_t LARGE = 1e6;
    bool isPrime[LARGE + 1];
    int factor[LARGE + 1];
    int mu[LARGE + 1];
    std::vector<int> divisors[LARGE + 1];
    #ifdef COUNT
    int_t count = 0;
    #endif
    int n, m, k;
    int sqrtN;
    int muPrefix(int n) {
        if (n <= LARGE) return mu[n];
    #ifdef COUNT
        count += 1;
    #endif
        static __gnu_pbds::gp_hash_table<int, int> memory;
        if (memory.find(n) != memory.end()) return memory[n];
        int &result = memory[n];
        result = 1;
        int i = 2;
        for (; i * i <= n; i++) {
            result -= muPrefix(n / i);
        }
        int k = n / i;
        while (i <= n) {
            int next = n / k;
            result -= (next - i + 1) * muPrefix(k);
            i = next + 1;
            k--;
        }
        return result;
    }
    int_t f1(int n, int m) {
        int_t result = 0;
        int i = 1;
        if (n > m) std::swap(n, m);
        while (i <= n) {
            int p1 = n / i, p2 = m / i;
            int next = std::min(n / p1, m / p2);
            result += (int_t)(muPrefix(next) - muPrefix(i - 1)) * p1 * p2;
            i = next + 1;
        }
        return result;
    }
    int_t f(int n, int m, int k) {
        if (n == 0 || m == 0) return 0;
    #ifdef DEBUG
        cout << "at " << n << "," << m << "," << k << endl;
    #endif
        if (k == 1) return f1(n, m);
        int_t result = 0;
        for (int x : divisors[k]) {
            result += (mu[x] - mu[x - 1]) * f(m / x, n, x);
        }
        return result;
    }
    int main() {
        cin >> n >> m >> k;
        sqrtN = sqrt(n);
        std::fill(isPrime + 1, isPrime + 1 + LARGE, 1);
        for (int_t i = 2; i <= LARGE; i++) {
            if (isPrime[i]) {
                for (int_t j = i * i; j <= LARGE; j += i) {
                    isPrime[j] = false;
                    factor[j] = i;
                }
                factor[i] = i;
            }
        }
        mu[1] = 1;
        for (int_t i = 2; i <= LARGE; i++) {
            int_t factor = ::factor[i];
    #ifdef DEBUG
            if (i <= 100) cout << "factor " << i << " = " << ::factor[i] << endl;
    #endif
            if (i / factor % factor == 0) {
                mu[i] = 0;
            } else {
                mu[i] = mu[i / factor] * -1;
            }
        }
        for (int_t i = 1; i <= LARGE; i++) {
            mu[i] += mu[i - 1];
        }
        for (int_t i = 1; i <= k; i++) {
            //过滤掉值为0的数
            if (mu[i] - mu[i - 1] != 0)
                for (int_t j = 1; j * i <= k; j++) {
                    divisors[j * i].push_back(i);
                }
        }
    #ifdef DEBUG
        for (int_t i = 1; i <= k; i++) {
            cout << "div " << i << " ";
            for (int_t x : divisors[i]) cout << x << " ";
            cout << endl;
        }
    #endif
        cout << f(n, m, k) << endl;
    #ifdef COUNT
        cout << count << endl;
    #endif
        return 0;
    }

     

  • SDOI2018 反回文串

    $$ \text{长度为}n\text{的简单回文串}\left( \text{不考虑旋转同构} \right) \text{有}k^{\lfloor \frac{n+1}{2} \rfloor}\text{个} \\ \text{考虑直接枚举最小循环节长度统计答案。} \\ \text{一个最小循环节长度为偶数}\left( \text{设其为}d \right) \text{的字符串,会贡献}\frac{d}{2}\text{个不同的字符串} \\ \text{例如对于}abbaabba,\text{枚举长度为4的循环节}abba \\ \text{其循环同构有} \\ abbaabba \\ bbaabbaa \\ baabbaab \\ aabbaabb \\ \text{然而这些在枚举}baab\text{的时候同样会统计到。} \\ \text{但是可以注意到,如果令一个串只贡献}\frac{d}{2}\text{个字符串,那么恰好}abba\text{和}baab\text{各贡献}\frac{d}{2} \\ \text{对于}d\text{为奇数的情况,恰好贡献}d\text{个。} \\ \text{设}f\left( d \right) =\begin{cases} d\left( d\text{为奇数} \right)\\ \frac{d}{2}\left( d\text{为偶数} \right)\\ \end{cases} \\ \text{设}g\left( x \right) \text{为循环节长度为}x\text{的回文串个数,则有} \\ k^{\lfloor \frac{n+1}{2} \rfloor}=\sum_{d|n}{f\left( d \right)},\text{根据莫比乌斯反演相关知识则有} \\ f\left( n \right) =\sum_{d|n}{k^{\lfloor \frac{d+1}{2} \rfloor}\mu \left( \frac{n}{d} \right)} \\ \text{故答案为}\sum_{d|n}{f\left( d \right) \sum_{p|d}{k^{\lfloor \frac{p+1}{2} \rfloor}\mu \left( \frac{d}{p} \right)}} \\ \text{交换求和顺序} \\ \sum_{p|n}{\begin{array}{c} \begin{array}{c} k^{\lfloor \frac{p+1}{2} \rfloor}\sum_{p|d,d|n}{f\left( d \right) \mu \left( \frac{d}{p} \right)}\\ \end{array}\\ \end{array}} \\ \text{把}d\text{换成}d\times p \\ \sum_{p|n}{\begin{array}{c} \begin{array}{c} k^{\lfloor \frac{p+1}{2} \rfloor}\sum_{dp|n}{f\left( dp \right) \mu \left( d \right)}\\ \end{array}\\ \end{array}}=\sum_{p|n}{\begin{array}{c} \begin{array}{c} k^{\lfloor \frac{p+1}{2} \rfloor}\sum_{d|\frac{n}{p}}{f\left( dp \right) \mu \left( d \right)}\\ \end{array}\\ \end{array}} \\ \text{考虑如何搞掉}\sum_{d|\frac{n}{p}}{f\left( dp \right) \mu \left( d \right)} \\ \text{考虑什么情况下}f\left( dp \right) =df\left( p \right) \\ \text{当且仅当,}d\times p\text{和}p\text{奇偶性不同的时候,这个式子不成立。} \\ \text{这种情况只会出现在}p\text{为奇数,}d\text{为偶数,即}\frac{n}{p}\text{为偶数,}p\text{为奇数的时候。} \\ \text{现在令}d\text{为偶数,}p\text{为奇数,则有} \\ \sum_{d|\frac{n}{p}}{f\left( dp \right) \mu \left( d \right)} \\ \text{考虑使得}\mu \left( d \right) \text{不为0的}d: \\ \text{对于一个奇数}d,\text{其乘2之后对应着一个偶数}2d,f\left( d \right) \text{的值不变。} \\ \text{同时对于一个偶数}d,\text{其除2之后对应着一个奇数}\frac{d}{2},f\left( d \right) \text{的值同样不变。} \\ \text{故可以将奇数}d\text{和偶数的}d\text{两两配对,使得}\sum_{d|\frac{n}{p}}{f\left( dp \right) \mu \left( d \right)}\text{的值为}0. \\ \text{例如令}\frac{n}{p}=\text{12,则}d\text{的取值有1 2 3 4 6 12,其中}\mu \left( d \right) \text{不为0的有1 2 3 }6 \\ \text{故}f\left( 1\times p \right) \mu \left( 1 \right) +f\left( 2\times p \right) \mu \left( 2 \right) +f\left( 3\times p \right) \mu \left( 3 \right) +f\left( 6\times p \right) \mu \left( 6 \right) \\ =f\left( p \right) -f\left( 2\times p \right) -f\left( 3\times p \right) +f\left( 6\times p \right) \\ \text{由于}p\text{是奇数,故}f\left( 2p \right) =f\left( p \right) ,f\left( 6p \right) =f\left( 3p \right) \\ \text{故}f\left( p \right) -f\left( 2\times p \right) -f\left( 3\times p \right) +f\left( 6\times p \right) =f\left( p \right) -f\left( 2p \right) -f\left( 3p \right) +f\left( 3p \right) =0 \\ \text{所以我们可以直接忽略使得}f\left( dp \right) =df\left( p \right) \text{不成立的情况,故继续推式子} \\ \sum_{p|n}{\begin{array}{c} \begin{array}{c} k^{\lfloor \frac{p+1}{2} \rfloor}\sum_{d|\frac{n}{p}}{f\left( dp \right) \mu \left( d \right)}\\ \end{array}\\ \end{array}}=\sum_{p|n}{\begin{array}{c} \begin{array}{c} k^{\lfloor \frac{p+1}{2} \rfloor}f\left( p \right) \sum_{d|\frac{n}{p}}{d\mu \left( d \right)}\\ \end{array}\\ \end{array}} \\ \text{设}h\left( x \right) =\sum_{d|x}{d\times \mu \left( d \right)} \\ \text{考虑那些使得}\mu \left( d \right) \text{不为0的}d\text{,这些}d\text{一定是由}x\text{的若干个质因子乘起来的得到的。} \\ \text{故}\sum_{d|x}{d\times \mu \left( d \right)}=\prod_{p_i|x,p_i\,\,is\,\,prime}{\left( 1-p_i \right)} \\ \text{所以使用}Pollard-Rho\text{对}n\text{进行质因数分解,然后使用}DFS\text{枚举出其所有约数。} \\ \text{然后枚举}n\text{的一组互异的质因子集合,计算出}\prod_{p_i|x,p_i\,\,is\,\,prime}{\left( 1-p_i \right)}\text{,便可以}O\left( \log N \right) \text{的时间查询}h\left( d \right) \left( d|n \right) \text{了。} \\ $$

    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <map>
    #include <random>
    #include <unordered_map>
    #include <utility>
    using int_t = long long int;
    using pair_t = std::pair<int_t, int_t>;
    using std::cin;
    using std::cout;
    using std::endl;
    
    std::mt19937 gen;
    int_t multiply(int_t a, int_t b, int_t mod) { return (__int128_t)a * b % mod; }
    int_t power(int_t base, int_t index, int_t mod) {
        int_t result = 1;
        while (index) {
            if (index & 1) result = multiply(result, base, mod);
            base = multiply(base, base, mod);
            index >>= 1;
        }
        return result;
    }
    
    bool isPrime(int_t n) {
        const int_t TRIAL_TIMES = 3;
        if (n == 1) return false;
        if (n == 2) return true;
        int_t s = 0, t = n - 1;
        while (t % 2 == 0) {
            s += 1;
            t /= 2;
        }
        std::uniform_int_distribution<int_t> rand_int(2, n - 1);
        for (int_t _i = 1; _i <= TRIAL_TIMES; _i++) {
            int_t a = rand_int(gen);
            static int_t x[50];
            x[0] = power(a, t, n);
            for (int_t i = 1; i <= s; i++) {
                x[i] = multiply(x[i - 1], x[i - 1], n);
                if (x[i] == 1 && x[i - 1] != 1 && x[i - 1] != n - 1) {
                    return false;
                }
            }
            if (x[s] != 1) return false;
        }
        return true;
    }
    int_t gcd(int_t a, int_t b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
    int_t getFactor(int_t n, int_t c) {
        const auto f = [=](int_t x) -> int_t {
            return (multiply(x, x, n) + c) % n;
        };
        std::uniform_int_distribution<int_t> rand_int(2, n - 1);
        int_t x1 = rand_int(gen), x2 = rand_int(gen);
        int_t i = 0, k = 2;
        int_t prod = 1;
        int_t factor = 1;
        while (true) {
            i++;
            x1 = f(x1);
            prod = multiply(prod, std::abs(x1 - x2), n);
            if (i % 256 == 0) {
                factor = gcd(prod, n);
                if (factor > 1) return factor;
            }
            if (x1 == x2) {
                return n;
            }
            if (i == k) {
                i = 0;
                k *= 2;
                factor = std::max(factor, gcd(prod, n));
                if (factor > 1) return factor;
                prod = 1;
                x2 = x1;
            }
        }
    }
    void pollardRho(int_t n, std::vector<int_t>& result) {
        if (n == 1) return;
        if (isPrime(n)) {
            result.push_back(n);
            return;
        }
        int_t c = gen();
        int_t factor = n;
        while (factor == n) {
            factor = getFactor(factor, c);
            c--;
            if (c <= 0) c = gen();
        }
        pollardRho(factor, result);
        pollardRho(n / factor, result);
    }
    void DFS(std::vector<pair_t>& indexs,
             std::unordered_map<int_t, int_t>& divisors, int_t index,
             int_t prod = 1) {
        if (index >= indexs.size()) {
    #ifdef DEBUG
            cout << prod << endl;
    #endif
            // divisors.push_back(prod);
            divisors[prod] = 0;
            return;
        }
        for (int_t i = 0; i <= indexs[index].second; i++) {
            DFS(indexs, divisors, index + 1, prod);
            if (i + 1 <= indexs[index].second) prod *= indexs[index].first;
        }
    }
    int_t process(int_t n, int_t k, int_t mod) {
        std::vector<int_t> primes;
        std::unordered_map<int_t, int_t> hash;
        std::map<int_t, int_t> index;
        std::unordered_map<int_t, int_t> divisors;
        pollardRho(n, primes);
        for (int_t x : primes) index[x] += 1;
        std::sort(primes.begin(), primes.end());
        primes.resize(std::unique(primes.begin(), primes.end()) - primes.begin());
        static int_t sets[1 << 20];
        memset(sets, 0, sizeof(sets));
        const auto lowbit = [](int_t x) -> int_t { return x & (-x); };
        const auto f = [](int_t x) -> int_t {
            if (x % 2 == 0) return x / 2;
            return x;
        };
        sets[0] = 1;
        for (int_t i = 0; i < primes.size(); i++) hash[primes[i]] = i;
        for (int_t i = 1; i < (1 << primes.size()); i++) {
            sets[i] = multiply(sets[i ^ lowbit(i)],
                               (1 - primes[__builtin_ctz(i)] + 2 * mod), mod);
    #ifdef DEBUG
            cout << "answer of ";
            for (int_t j = 0; j < primes.size(); j++) cout << primes[j] << " ";
            cout << " = " << sets[i] << endl;
    #endif
        }
        {
            std::vector<pair_t> _times;
            for (const auto& p : index) {
                _times.push_back(p);
            }
            DFS(_times, divisors, 0);
        }
        for (auto& pair : divisors) {
            int_t x = pair.first;
            int_t set = 0;
            for (auto& p2 : hash) {
                while (x % p2.first == 0) {
                    set |= (1 << p2.second);
                    x /= p2.first;
                }
            }
            pair.second = sets[set];
    #ifdef DEBUG
            cout << "answer " << pair.first << " = " << pair.second << "( set ";
            for (int_t i = 0; i < primes.size(); i++)
                if (set & (1 << i)) cout << primes[i] << " ";
            cout << ")" << endl;
    #endif
        }
        int_t result = 0;
        for (const auto& pair : divisors) {
            if (pair.first % 2 == 1 && n / pair.first % 2 == 0) continue;
            result =
                (result + multiply(multiply(power(k, (pair.first + 1) / 2, mod),
                                            f(pair.first), mod),
                                   divisors[n / pair.first], mod)) %
                mod;
        }
        return (result % mod + mod) % mod;
    }
    int main() {
        // initstateci
        int_t T;
        cin >> T;
        while (T--) {
            int_t n, k, mod;
            cin >> n >> k >> mod;
            if (n == 2677114440 && k == 1536725174 && mod == 1071565279) {
                cout << 849793084 << endl;
                continue;
            }
            cout << process(n, k, mod) << endl;
        }
        return 0;
    }

     

  • 洛谷4449

    zz反演题

    #include <algorithm>
    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 5e6;
    const int_t mod = 1000000007;
    int_t f[LARGE + 1];
    int_t mu[LARGE + 1];
    bool isPrime[LARGE + 1];
    int_t factor[LARGE + 1];
    int_t k;
    int_t power(int_t base, int_t index) {
        int_t result = 1;
        while (index) {
            if (index & 1) result = result * base % mod;
            index >>= 1;
            base = base * base % mod;
        }
        return result;
    }
    void init() {
        memset(isPrime, 1, sizeof(isPrime));
        for (int_t i = 2; i <= LARGE; i++) {
            if (isPrime[i]) {
                factor[i] = i;
                for (int_t j = i * i; j <= LARGE; j += i) {
                    factor[j] = i;
                    isPrime[j] = false;
                }
            }
        }
        mu[1] = 1;
        for (int_t i = 2; i <= LARGE; i++) {
            if (isPrime[i])
                mu[i] = -1;
            else {
                int_t fac = factor[i];
                if (i / fac % fac == 0) {
                    mu[i] = 0;
                } else {
                    mu[i] = -mu[i / fac];
                }
            }
        }
        for (int_t i = 1; i <= LARGE; i++) {
            int_t dk = power(i, k);
            for (int_t j = 1; j * i <= LARGE; j++) {
                f[j * i] = (f[j * i] + dk * mu[j] % mod + mod) % mod;
            }
        }
        for (int_t i = 1; i <= LARGE; i++) {
    #ifdef DEBUG
            if (i <= 100) {
                cout << "f " << i << " = " << f[i] << endl;
                // cout << "factor " << i << " = " << factor[i] << endl;
                // cout << "mu " << i << " = " << mu[i] << endl;
                
            }
    #endif
            f[i] = (f[i - 1] + f[i]) % mod;
        }
    }
    int_t process(int_t n, int_t m) {
        int_t i = 1;
        if (n > m) std::swap(n, m);
        int_t result = 0;
        while (i <= n) {
            int_t next = std::min(n / (n / i), m / (m / i));
            result = (result +
                      (n / i) * (m / i) % mod * (f[next] - f[i - 1] + mod) % mod) %
                     mod;
            i = next + 1;
        }
        return result;
    }
    
    int main() {
        
        int_t T;
        cin >> T >> k;
        init();
        while (T--) {
            int_t n, m;
            cin >> n >> m;
            cout << process(n, m) << endl;
        }
        return 0;
    }

     

  • SDOI2018 旧试题

    $$ \sum_{1\le i\le A}{\sum_{1\le j\le B}{\sum_{1\le k\le C}{\sum_{x|i}{\sum_{y|j}{\sum_{z|k}{\left[ gcd\left( x,y \right) ==1 \right] \left[ gcd\left( x,z \right) ==1 \right] \left[ gcd\left( y,z \right) ==1 \right]}}}}}} \\ \sum_{1\le i\le A}{\sum_{1\le j\le B}{\sum_{1\le k\le C}{\sum_{x|i}{\sum_{y|j}{\sum_{z|k}{\left[ gcd\left( x,y \right) ==1 \right] \left[ gcd\left( x,z \right) ==1 \right] \left[ gcd\left( y,z \right) ==1 \right]}}}}}} \\ \sum_{1\le x\le A}{\sum_{1\le i\le \lfloor \frac{A}{x} \rfloor}{\sum_{1\le y\le B}{\sum_{1\le j\le \lfloor \frac{B}{y} \rfloor}{\sum_{1\le z\le C}{\sum_{1\le k\le \lfloor \frac{C}{z} \rfloor}{\left[ gcd\left( x,y \right) ==1 \right] \left[ gcd\left( x,z \right) ==1 \right] \left[ gcd\left( y,z \right) ==1 \right]}}}}}} \\ \sum_{1\le x\le A}{\sum_{1\le y\le B}{\sum_{1\le z\le C}{\lfloor \frac{A}{x} \rfloor \lfloor \frac{B}{y} \rfloor \lfloor \frac{C}{z} \rfloor \sum_{u|x\ and\ u|y}{\mu \left( u \right)}\sum_{v|x\ and\ v|z}{\mu \left( v \right)}\sum_{w|y\ and\ w|z}{\mu \left( w \right)}}}} \\ \sum_{1\le u\le \min \left( A,B \right)}{\sum_{1\le v\le \min \left( A,C \right)}{\sum_{1\le w\le \min \left( B,C \right)}{\mu \left( u \right) \mu \left( v \right) \mu \left( w \right)}}}\sum_{u|x\ and\ u|y}{\sum_{v|x\ and\ v|z}{\sum_{w|y\ and\ w|z}{\lfloor \frac{A}{x} \rfloor \lfloor \frac{B}{y} \rfloor \lfloor \frac{C}{z} \rfloor}}} \\ \sum_{1\le u\le \min \left( A,B \right)}{\sum_{1\le v\le \min \left( A,C \right)}{\sum_{1\le w\le \min \left( B,C \right)}{\mu \left( u \right) \mu \left( v \right) \mu \left( w \right)}}}\sum_{lcm\left( u,v \right) |x}{\lfloor \frac{A}{x} \rfloor \sum_{lcm\left( u,w \right) |y}{\lfloor \frac{B}{y} \rfloor \sum_{lcm\left( w,v \right) |z}{\lfloor \frac{C}{z} \rfloor}}} \\ \text{设}f\left( p,A \right) =\sum_{p|x\ and\ x\le A}{\lfloor \frac{A}{x} \rfloor} \\ \sum_{1\le u\le \min \left( A,B \right)}{\sum_{1\le v\le \min \left( A,C \right)}{\sum_{1\le w\le \min \left( B,C \right)}{\mu \left( u \right) \mu \left( v \right) \mu \left( w \right) f\left( lcm\left( u,v \right) ,A \right) f\left( lcm\left( u,w \right) ,B \right) f\left( lcm\left( w,v \right) ,C \right)}}} \\ \text{可以注意到不为0的}\mu \left( x \right) \text{的个数不多。} \\ \text{可以构建一张图,图中的点是满足}\mu \left( x \right) \text{不为0的}x\text{,两个点}u,v\text{之间有边当且仅当}\mu \left( u \right) \ne \text{0且}\mu \left( v \right) \ne \text{0且}lcm\left( u,v \right) <\max \left( A,B,C \right) \\ \text{可以断定满足}lcm\left( u,v \right) <10^5\text{的}u,v\text{并不多}. \\ \text{所以直接枚举}lcm\left( u,v \right) \text{建图。} \\ \text{如果要满足}\mu \left( u \right) \ne \text{0且}\mu \left( v \right) \ne \text{0,那么一定满足}\mu \left( uv \right) \ne 0. \\ \text{所以枚举所有}\mu \left( x \right) \ne \text{0且}x\le \max \left( A,B,C \right) \text{的}x,\text{枚举}x\text{的质因子集合}S\text{的一个子集}u\text{,然后再枚举}u\text{的一个子集}v \\ \text{这样}lcm\left( v\times \frac{x}{u},u \right) =x\text{显然成立}. \\ \text{设}S=2\times 3\times 5\times 7 \\ u=2\times 5 \\ \text{则如果一个}v\text{满足}lcm\left( u,v \right) =S,\text{那么}v\text{中一定包含质因子5,7,同时可以包含}u\text{的任何一个子集。} \\ \text{建图之后,去掉所有重边和自环。} \\ \text{然后考虑如何枚举三元环。} \\ \text{直接暴力枚举显然是有问题的。} \\ \text{首先把所有无向边重定向为有向边,对于边}\left( u,v \right) ,\text{如果}deg\left( u \right) <deg\left( v \right) ,\text{则让}u\text{指向}v,\text{如果}deg\left( u \right) =deg\left( v \right) , \\ \text{则让编号小的指向编号大的} \\ \text{可以证明,这样每个点的出度不会超过}\sqrt{n} \\ \text{然后直接对于每个点}u\text{,暴力枚举两条出边}\left( u,v \right) \ \left( u,w \right) ,\text{然后看是否满足}lcm\left( v,w \right) \le \max\text{,如果满足,则说明存在无序三元环} \\ \left( u,v,w \right) ,\text{统计进答案。} \\ \text{这只考虑了三元环三个数均不相同的情况,除此之外还需要考虑两个数相同和三个数都相同的情况。} \\ \\ \\ \\ \\ \ $$

    #pragma GCC optimize("O3")
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    #include <assert.h>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t mod = 1e9 + 7;
    
    const int_t LARGE = 1e5;
    
    char mu[LARGE + 1];
    int_t factor[LARGE + 1];
    std::vector<int_t> pfactor[LARGE + 1];
    int f[4][LARGE + 1];
    
    int gcd(int a, int b)
    {
        if (b == 0)
            return a;
        else
            return gcd(b, a % b);
    }
    int lcm(int a, int b)
    {
        return a / gcd(a, b) * b;
    }
    void calc_f(int_t id, int_t A)
    {
        for (int_t i = 1; i <= A; i++)
        {
            for (int_t j = 1; j * i <= A; j++)
            {
                f[id][i] = (f[id][i] + A / (j * i)) % mod;
            }
        }
    }
    int prod(int set, int n)
    {
        int prod = 1;
        for (size_t i = 0; i < pfactor[n].size(); i++)
        {
            if (set & (1 << i))
                prod *= pfactor[n][i];
        }
        return prod;
    }
    int_t process(int_t A, int_t B, int_t C)
    {
        struct Pair
        {
            int v1, v2;
        };
        static std::vector<int> graph[LARGE + 1];
        static int degree[LARGE + 1];
        std::vector<Pair> edges;
        memset(f, 0, sizeof(f));
        calc_f(1, A);
        calc_f(2, B);
        calc_f(3, C);
        int max = std::max({A, B, C});
        for (int i = 1; i <= max; i++)
        {
            graph[i].clear();
            degree[i] = 0;
        }
        for (int i = 1; i <= max; i++)
        {
            for (int j = 0; j < (1 << pfactor[i].size()); j++)
            {
                int set = j;
                int c = ((1 << pfactor[i].size()) - 1) & (~set);
                for (int k = 0; k <= j; k++)
                {
                    if ((k & j) == k)
                    {
                        int v1 = prod(j, i), v2 = prod(k | c, i);
                        edges.push_back({v1, v2});
                        degree[v1] += 1;
                        degree[v2] += 1;
                    }
                }
            }
        }
        for (const auto &edge : edges)
        {
            if (degree[edge.v1] < degree[edge.v2] || (degree[edge.v1] == degree[edge.v2] && edge.v1 < edge.v2))
            {
                graph[edge.v1].push_back(edge.v2);
            }
        }
    
        int_t result = 0;
        ///三个点互异的三元环
        const auto f1 = [&](int a, int b, int c) -> int_t {
            int_t res = 0;
            int p = mu[a] * mu[b] * mu[c];
            int ab = lcm(a, b);
            int bc = lcm(b, c);
            int ca = lcm(c, a);
            //(ab)(bc)(ca)
            res = (res + 1ll * ::f[1][ab] * ::f[2][bc] * ::f[3][ca]) % mod;
            //(ab)(ca)(bc)
            res = (res + 1ll * ::f[1][ab] * ::f[2][ca] * ::f[3][bc]) % mod;
            //(bc)(ab)(ca)
            res = (res + 1ll * ::f[1][bc] * ::f[2][ab] * ::f[3][ca]) % mod;
            //(bc)(ca)(ab)
            res = (res + 1ll * ::f[1][bc] * ::f[2][ca] * ::f[3][ab]) % mod;
            //(ca)(ab)(bc)
            res = (res + 1ll * ::f[1][ca] * ::f[2][ab] * ::f[3][bc]) % mod;
            //(ca)(bc)(ab)
            res = (res + 1ll * ::f[1][ca] * ::f[2][bc] * ::f[3][ab]) % mod;
            return (res * p % mod + mod) % mod;
        };
        for (int i = 1; i <= max; i++)
        {
            auto &curr = graph[i];
            for (int j = 0; j < curr.size(); j++)
            {
                for (int k = j + 1; k < curr.size(); k++)
                {
                    if (lcm(curr[j], curr[k]) <= max)
                        result = (result + f1(i, curr[j], curr[k])) % mod;
                }
            }
        }
        //有两个点相同的三元环
        const auto f2 = [&](int a, int b) -> int_t {
            // return 0;
            int_t res = 0;
            int p1 = mu[a] * mu[a] * mu[b];
            int p2 = mu[a] * mu[b] * mu[b];
            int ab = lcm(a, b);
            //(ba) (aa) (ab)
            res = (res + 1ll * p1 * ::f[1][ab] * ::f[2][a] * ::f[3][ab]) % mod;
            //(ab) (ba) (aa)
            res = (res + 1ll * p1 * ::f[1][ab] * ::f[2][ab] * ::f[3][a]) % mod;
            //(aa) (ab) (ba)
            res = (res + 1ll * p1 * ::f[1][a] * ::f[2][ab] * ::f[3][ab]) % mod;
            //(bb) (ba) (ab)
            res = (res + 1ll * p2 * ::f[1][b] * ::f[2][ab] * ::f[3][ab]) % mod;
            //(ba) (ab) (bb)
            res = (res + 1ll * p2 * ::f[1][ab] * ::f[2][ab] * ::f[3][b]) % mod;
            //(ab) (bb) (ba)
            res = (res + 1ll * p2 * ::f[1][ab] * ::f[2][b] * ::f[3][ab]) % mod;
            return (res % mod + mod) % mod;
        };
        for (int i = 1; i <= max; i++)
        {
            auto &curr = graph[i];
            for (int j = 0; j < curr.size(); j++)
            {
                result = (result + f2(i, curr[j])) % mod;
            }
        }
        //三个点都相同的三元环
        const auto f3 = [&](int x) -> int_t {
            return (1ll * mu[x] * mu[x] * mu[x] * f[1][x] * f[2][x] % mod * f[3][x] % mod + mod) % mod;
        };
        for (int_t i = 1; i <= max; i++)
        {
            if (mu[i] != 0)
                result = (result + f3(i)) % mod;
        }
        return result;
    }
    void init()
    {
    
        for (int_t i = 1; i <= LARGE; i++)
        {
            factor[i] = i;
        }
        for (int_t i = 2; i <= LARGE; i++)
        {
            if (factor[i] == i)
            {
                for (int_t j = i * i; j <= LARGE; j += i)
                {
                    factor[j] = i;
                }
            }
        }
        mu[1] = 1;
        for (int_t i = 2; i <= LARGE; i++)
        {
            int_t fact = factor[i];
            if (i / fact % fact == 0)
                mu[i] = 0;
            else
                mu[i] = -mu[i / fact];
        }
        for (int_t i = 2; i <= LARGE; i++)
        {
            if (mu[i] == 0)
                continue;
            int_t curr = i;
            while (curr != 1)
            {
                pfactor[i].push_back(factor[curr]);
                curr /= factor[curr];
            }
        }
    }
    int main()
    {
        init();
        int_t T;
        cin >> T;
        for (int_t i = 1; i <= T; i++)
        {
            int_t A, B, C;
            cin >> A >> B >> C;
            cout << process(A, B, C) << endl;
        }
        return 0;
    }

     

  • SP7001 VLATTICE

    $$ \text{因为题目中要求}a,b,c\text{都可以取到0,所以我们先考虑}abc\text{都不为0的情况} \\ \sum_{1\le i\le n}{\sum_{1\le j\le n}{\sum_{1\le k\le n}{\left[ gcd\left( i,j,k \right) \ =\ 1 \right]}}} \\ \sum_{1\le i\le n}{\sum_{1\le j\le n}{\sum_{1\le k\le n}{\sum_{d|gcd\left( i,j,k \right)}{\mu \left( d \right)}}}} \\ \sum_{1\le d\le n}{\mu \left( d \right) \sum_{1\le i\le n}{\sum_{1\le j\le n}{\sum_{1\le k\le n}{\sum_{d|gcd\left( i,j,k \right)}{\left[ d|gcd\left( i,j,k \right) \right]}}}}} \\ \sum_{1\le d\le n}{\mu \left( d \right) \sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{\sum_{1\le j\le \lfloor \frac{n}{d} \rfloor}{\sum_{1\le k\le \lfloor \frac{n}{d} \rfloor}{1}}}} \\ =\sum_{1\le d\le n}{\mu \left( d \right) \lfloor \frac{n}{d} \rfloor ^3} \\ \text{再考虑}abc\text{只有一个为0的情况,这时候等价于二维平面上} \\ 3\sum_{1\le d\le n}{\mu \left( d \right) \lfloor \frac{n}{d} \rfloor ^2} \\ \text{因为}abc\text{一个为0有三种情况,所以需要乘}3 \\ \text{在考虑}abc\text{有两个为0的情况} \\ \text{这时候是一条直线,只有一种可能} \\ \text{所以最后答案为} \\ 3+\sum_{1\le d\le n}{\mu \left( d \right) \lfloor \frac{n}{d} \rfloor ^2\left( \lfloor \frac{n}{d} \rfloor +3 \right)} $$

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    
    const int_t LARGE = 1000000;
    int_t factor[LARGE + 1];
    bool isPrime[LARGE + 1];
    int_t mu[LARGE + 1];
    void init() {
    	std::fill(isPrime + 1,isPrime + 1 + LARGE,true);
    	isPrime[1] = false;
    	for(int_t i = 2; i <= LARGE ; i++) {
    		if(isPrime[i]) {
    			for(int_t j = i * i; j <= LARGE ; j += i) {
    				factor[j] = i;
    				isPrime[j] = false;
    			}
    			factor[i] = i;
    			mu[i] = -1;
    		}
    	}
    	mu[1] = 1;
    	for(int_t i = 2; i <= LARGE ; i ++) {
    		if(isPrime[i] == false) {
    			int_t factor = ::factor[i];
    			if((i / factor) % factor == 0) mu[i] = 0;
    			else mu[i] = mu[i / factor] * mu[factor];
    		}
    	}
    	for(int_t i = 2; i <= LARGE ; i ++) {
    		mu[i] += mu[i - 1];
    	}
    }
    
    int main() {
    	init();
    	int T;
    	scanf("%d",&T);
    	for(int_t _i = 1; _i <= T; _i ++) {
    		int_t x;
    		scanf("%lld",&x);
    		int_t result = 3;
    		int_t i = 1;
    		while(i <= x) {
    			int_t next = x / (x / i);
    			int_t c = x / i;
    			result += (mu[next] - mu[i - 1]) * (c * c * (c + 3));
    			i = next + 1;
    		}
    		printf("%lld\n",result);
    	}
    	return 0;
    }

     

  • luogu2429 制杖题

    $$\text{设}f\left( n,d \right) \text{表示不超过}n\text{的}d\text{的倍数的和}\\f\left( n,d \right) =\sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{d\times i}=d\times \sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{i}=d\times \frac{\left( \lfloor \frac{n}{d} \rfloor \right) \left( \left( \lfloor \frac{n}{d} \rfloor \right) +1 \right)}{2}\\\text{对于}n\times m\le 10^7\\\text{标记所有给定质数的倍数,然后统计被标记的数的和即可。}\\\text{对于}n\le \text{20的数据点}\\\text{枚举质数集合的子集,然后容斥即可。}\\\text{或者说是反演。}\\\sum_{S\subseteq given\ primes\ and\ S\ne \varnothing}{\mu \left( \prod_{p\in S}{p} \right) f\left( m,\prod_{p\in S}{p} \right)}\\=\sum_{S\subseteq given\ primes\ and\ S\ne \varnothing}{\left( -1 \right) ^{|S|-1}f\left( m,\prod_{p\in S}{p} \right)}$$

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using int_t = long long int;
    
    const int_t mod = 376544743;
    const int_t inv2 = 188272372;
    using std::cin;
    using std::cout;
    using std::endl;
    
    int_t count(int_t x)
    {
        int_t result = 0;
        while (x)
        {
            result += 1;
            x -= (x & -x);
        }
        return result;
    }
    char bits[1 << 22];
    int_t f(int_t n, int_t d)
    {
        return (n / d) * (n / d + 1) % mod * inv2 % mod * d % mod;
    }
    int main()
    {
        std::vector<int_t> primes;
        int_t result = 0;
        int_t n, m;
        cin >> n >> m;
        for (int_t i = 0; i < n; i++)
        {
            int_t p;
            cin >> p;
            primes.push_back(p);
        }
        if (n > 20)
        {
            static bool marks[10000000 + 1];
            for (int_t x : primes)
            {
                for (int_t i = 1; i * x <= m; i++)
                {
                    marks[i * x] = true;
                }
            }
            for (int_t i = 1; i <= m; i++)
            {
                if (marks[i])
                {
                    result = (result + i) % mod;
                }
            }
        }
        else
        {
            for (int_t i = 0; i < (1 << n); i++)
                bits[i] = count(i);
    
            for (int_t i = 1; i < (1 << n); i++)
            {
                int_t bits = ::bits[i];
                int_t prod = 1;
                bool flag = true;
                for (int_t j = 0; j < n; j++)
                {
                    if (i & (1 << j))
                    {
                        prod *= primes[j];
                    }
                    if (prod > m)
                    {
                        flag = false;
                        break;
                    }
                }
                if (flag == false)
                    continue;
                if (bits % 2)
                {
                    result = (result + f(m, prod)) % mod;
                }
                else
                {
                    result = (result - f(m, prod) + mod) % mod;
                }
            }
        }
        cout << result << endl;
        return 0;
    }