noya2_Library

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

View the Project on GitHub noya2ruler/noya2_Library

:heavy_check_mark: math/lcm_convolution.hpp

Depends on

Verified with

Code

#pragma once

#include <vector>
#include <cassert>

#include"../math/sieve.hpp"

namespace noya2 {

template <typename T>
std::vector<T> divisor_zeta_transform(const std::vector<T> &f){
    int n = f.size() - 1;
    reserve_sieve(n);
    auto F = f;
    for (const auto &p : sieve.primes){
        if (n < p) break;
        for (int i = 1; i * p <= n; i++) F[i * p] += F[i];
    }
    return F;
}

template <typename  T>
std::vector<T> divisor_mobius_transform(const std::vector<T> &F){
    int n = F.size() - 1;
    reserve_sieve(n);
    auto f = F;
    for (const auto &p : sieve.primes){
        if (n < p) break;
        for (int i = n / p; i >= 1; i--) f[i * p] -= f[i];
    }
    return f;
}

template <typename T>
std::vector<T> lcm_convolution(const std::vector<T> &a, const std::vector<T> &b){
    assert(a.size() == b.size());
    int n = a.size();
    auto ra = divisor_zeta_transform(a);
    auto rb = divisor_zeta_transform(b);
    for (int i = 0; i < n; i++) ra[i] *= rb[i];
    return divisor_mobius_transform(ra);
}

} // namespace noya2
#line 2 "math/lcm_convolution.hpp"

#include <vector>
#include <cassert>

#line 2 "math/sieve.hpp"

#line 5 "math/sieve.hpp"
#include <utility>

namespace noya2{

struct prime_sieve {
    static std::vector<int> primes, factor, mu;
    prime_sieve (int n = 1024){
        build(n);
    }
    static void reserve(int n){
        int sz = size();
        if (sz == 0){
            build(n);
            return ;
        }
        if (n <= sz) return ;
        while (sz < n) sz <<= 1;
        build(sz);
    }
    // n in [1, size()] is available
    static int size(){
        return (int)factor.size() - 1;
    }
  private:
    static void build(int n){
        primes.clear();
        factor.assign(n + 1, 0);
        mu.assign(n + 1, 1);
        for (int x = 2; x <= n; x++){
            if (factor[x] == 0){
                primes.emplace_back(x);
                factor[x] = x;
                mu[x] = -1;
            }
            for (int p : primes){
                if (x * p > n || p > factor[x]) break;
                factor[x * p] = p;
                mu[x * p] = (p == factor[x] ? 0 : -mu[x]);
            }
        }
    }
} sieve;
std::vector<int> prime_sieve::primes;
std::vector<int> prime_sieve::factor;
std::vector<int> prime_sieve::mu;

void reserve_sieve(int n){
    sieve.reserve(n);
}

int mobius_sieve(int n){
    assert(1 <= n && n <= sieve.size());
    return sieve.mu[n];
}

bool is_prime_sieve(int n){
    if (n <= 2) return n == 2;
    assert(n <= sieve.size());
    return sieve.factor[n] == n;
}

// pair(prime, exponent)
std::vector<std::pair<int, int>> factorize_sieve(int n){
    assert(1 <= n && n <= sieve.size());
    std::vector<std::pair<int, int>> ret;
    int pre = 0;
    while (n > 1){
        int p = sieve.factor[n];
        if (pre != p){
            ret.emplace_back(p, 1);
        }
        else {
            ret.back().second += 1;
        }
        pre = p;
        n /= p;
    }
    return ret;
}

std::vector<int> divisors_sieve(int n){
    assert(1 <= n && n <= sieve.size());
    std::vector<int> ret = {1};
    int pre = 0, w = 1;
    while (n > 1){
        int p = sieve.factor[n];
        int sz = ret.size();
        if (pre != p){
            w = ret.size();
        }
        ret.reserve(sz + w);
        for (int i = 0; i < w; i++){
            ret.emplace_back(ret[sz - w + i] * p);
        }
        pre = p;
        n /= p;
    }
    return ret;
}

} // namespace noya2
#line 7 "math/lcm_convolution.hpp"

namespace noya2 {

template <typename T>
std::vector<T> divisor_zeta_transform(const std::vector<T> &f){
    int n = f.size() - 1;
    reserve_sieve(n);
    auto F = f;
    for (const auto &p : sieve.primes){
        if (n < p) break;
        for (int i = 1; i * p <= n; i++) F[i * p] += F[i];
    }
    return F;
}

template <typename  T>
std::vector<T> divisor_mobius_transform(const std::vector<T> &F){
    int n = F.size() - 1;
    reserve_sieve(n);
    auto f = F;
    for (const auto &p : sieve.primes){
        if (n < p) break;
        for (int i = n / p; i >= 1; i--) f[i * p] -= f[i];
    }
    return f;
}

template <typename T>
std::vector<T> lcm_convolution(const std::vector<T> &a, const std::vector<T> &b){
    assert(a.size() == b.size());
    int n = a.size();
    auto ra = divisor_zeta_transform(a);
    auto rb = divisor_zeta_transform(b);
    for (int i = 0; i < n; i++) ra[i] *= rb[i];
    return divisor_mobius_transform(ra);
}

} // namespace noya2
Back to top page