cp-library

C++ Library for Competitive Programming

View the Project on GitHub emthrm/cp-library

:question: メビウス関数 (Möbius function) の数表2
(include/emthrm/math/mobius_mu_init2.hpp)

メビウス関数 (Möbius function)

$n \in \mathbb{N}^+$ に対して

\[\mu(n) \mathrel{:=} \begin{cases} 0 & (\exists p \in \mathbb{P},\ n \equiv 0 \pmod{p^2}), \\ (-1)^{\# \lbrace \text{相異なる素因数} \rbrace} & (\text{otherwise}) \end{cases}\]

で定義される $\mu(n)$ である。

が成り立つ。

メビウスの反転公式 (Möbius inversion formula)

\[f(n) = \sum_{d \mid n} g(d) \implies g(n) = \sum_{d \mid n} \mu \left(\frac{n}{d} \right) f(d) = \sum_{d \mid n} \mu(d) f \left(\frac{n}{d} \right)\]

時間計算量

  時間計算量
  $O(\sqrt{N})$
約数版  
数表 $O(N\log{\log{N}})$
数表2 $O\left(\sqrt{H}\log{\log{H}} + \frac{(H - L)\sqrt{H}}{\log{H}}\right)$ ?

仕様

名前 戻り値
int mobius_mu(long long n); $\mu(n)$

約数版

名前 戻り値 備考
template <typename T>
std::map<T, int> mobius_mu_focusing_on_divisor(T n);
$\lbrace n \text{ の約数 } d, \mu(d) \rbrace$ キーとして存在しないときは値 $0$ である。

数表

名前 戻り値
std::vector<int> mobius_mu_init(const int n); メビウス関数 $\mu(i)$ ($1 \leq i \leq n$) の数表
std::vector<int> mobius_mu_init2(const long long low, const long long high); メビウス関数 $\mu(i)$ ($\mathrm{low} \leq i < \mathrm{high}$) の数表

参考文献

TODO

Submissons

Depends on

Verified with

Code

#ifndef EMTHRM_MATH_MOBIUS_MU_INIT2_HPP_
#define EMTHRM_MATH_MOBIUS_MU_INIT2_HPP_

#include <numeric>
#include <vector>

#include "emthrm/math/prime_sieve.hpp"

namespace emthrm {

std::vector<int> mobius_mu_init2(const long long low, const long long high) {
  std::vector<int> mu(high - low, 1);
  std::vector<long long> tmp(high - low);
  std::iota(tmp.begin(), tmp.end(), low);
  if (low == 0 && high > 0) mu[0] = 0;
  long long root = 1;
  while ((root + 1) * (root + 1) < high) ++root;
  for (const int p : prime_sieve<true>(root)) {
    for (long long i = (low + p - 1) / p * p; i < high; i += p) {
      if ((i / p) % p == 0) {
        mu[i - low] = tmp[i - low] = 0;
      } else {
        mu[i - low] = -mu[i - low];
        tmp[i - low] /= p;
      }
    }
  }
  for (int i = 0; i < high - low; ++i) {
    if (tmp[i] > 1) mu[i] = -mu[i];
  }
  return mu;
}

}  // namespace emthrm

#endif  // EMTHRM_MATH_MOBIUS_MU_INIT2_HPP_
#line 1 "include/emthrm/math/mobius_mu_init2.hpp"



#include <numeric>
#include <vector>

#line 1 "include/emthrm/math/prime_sieve.hpp"



#line 6 "include/emthrm/math/prime_sieve.hpp"

namespace emthrm {

template <bool GETS_ONLY_PRIME>
std::vector<int> prime_sieve(const int n) {
  std::vector<int> smallest_prime_factor(n + 1), prime;
  std::iota(smallest_prime_factor.begin(), smallest_prime_factor.end(), 0);
  for (int i = 2; i <= n; ++i) {
    if (smallest_prime_factor[i] == i) [[unlikely]] prime.emplace_back(i);
    for (const int p : prime) {
      if (i * p > n || p > smallest_prime_factor[i]) break;
      smallest_prime_factor[i * p] = p;
    }
  }
  return GETS_ONLY_PRIME ? prime : smallest_prime_factor;
}

}  // namespace emthrm


#line 8 "include/emthrm/math/mobius_mu_init2.hpp"

namespace emthrm {

std::vector<int> mobius_mu_init2(const long long low, const long long high) {
  std::vector<int> mu(high - low, 1);
  std::vector<long long> tmp(high - low);
  std::iota(tmp.begin(), tmp.end(), low);
  if (low == 0 && high > 0) mu[0] = 0;
  long long root = 1;
  while ((root + 1) * (root + 1) < high) ++root;
  for (const int p : prime_sieve<true>(root)) {
    for (long long i = (low + p - 1) / p * p; i < high; i += p) {
      if ((i / p) % p == 0) {
        mu[i - low] = tmp[i - low] = 0;
      } else {
        mu[i - low] = -mu[i - low];
        tmp[i - low] /= p;
      }
    }
  }
  for (int i = 0; i < high - low; ++i) {
    if (tmp[i] > 1) mu[i] = -mu[i];
  }
  return mu;
}

}  // namespace emthrm
Back to top page