numberTheory.hpp

is assume to be a prime number, and for arbitrary module.

please use g++ -o main main.cpp -std=c++17 -O2 to complier examples below.

Prime

It is a singleton which has member isP, p, pi, and method: primePi and nthPrime

where

The key point is: if , then

See cnblog or origin paper package for detail.

Constraints

  • primePi(n):
  • nthPrime(n):

Complexity

  • primePi(n):
  • nthPrime(n):

Example

#include <bits/stdc++.h>
using LL = long long;
#include "cpplib/math/numberTheory.hpp"

int main() {
  std::cin.tie(nullptr)->sync_with_stdio(false);
  auto start = std::clock();
  auto& prime = Prime::Instance();
  std::cerr << "Init time used: " << (std::clock() - start) / 1000 << "ms" << std::endl;

  LL n = prime.primePi(123456789012LL);
  std::cout << n << '\n';

  LL x = prime.nthPrime(n);
  std::cout << x << '\n';

  // It must the same as n
  std::cout << prime.primePi(x) << '\n';

  std::cerr << "Total time used: " << (std::clock() - start) / 1000 << "ms" << std::endl;
  return 0;
}

Euler and Mobius

Euler's Totient function and Mobius function. The have many in common.

The key points are:

and then numberTheoryBlock tech is used to give a implement.

Example

#include <bits/stdc++.h>
#define clog(x) std::clog << (#x) << " is " << (x) << '\n';
using LL = long long;
#include "cpplib/math/numberTheory.hpp"

int main() {
  std::cin.tie(nullptr)->sync_with_stdio(false);
  auto start = std::clock();
  auto& euler = Euler::Instance();
  auto& Mobius = Mobius::Instance();
  std::cerr << "Init time used: " << (std::clock() - start) / 1000 << "ms" << '\n';

  int n = 1e9 + 7;
  clog(euler.getPhi(n));
  clog(euler.getSumPhi(n));

  clog(Mobius.getMu(n));
  clog(Mobius.getSumMu(n));
  clog(Mobius.getAbsSum(n));

  std::cerr << "Total time used: " << (std::clock() - start) / 1000 << "ms" << '\n';
  return 0;
}

npf

std::pair<std::vector<int>, std::vector<int>> npf(int N)
// auto [a, b] = npf(N)

init numbers of (multi) prime factors less than

Complexity

Example

  • 5

factor and Factor

std::vector<int> factor(int n, const std::vector<int>& sp)
std::vector<std::pair<int, int>> Factor(int n, const std::vector<int>& sp)

factor into prime number

Complexity

Example

primitiveRoot

int primitiveRoot(int n, const std::vector<int>& sp)

return smallest primitive root or 0 if not exist.

have primitive root if and only if where is prime number.

Complexity

Example

primitiveRootAll

std::vector<int> primitiveRootAll(int n, const std::vector<int>& sp)

return list of all primitive roots or empty if not exist

Complexity

Example

PollardRho

Pollard-rho algorithm is a probabilistic method for big number decomposition, which is based on big prime test probabilistic method: Miller-Rabin

bool PollardRho::rabin(LL n)
LL PollardRho::spf(LL n)
LL PollardRho::gpf(LL n, LL mxf = 1)

Complexity

babyStepGiantStep

find smallest non-negative s.t. , or

Constraints

  • is prime

Complexity

sqrtModp

int sqrtModp(int a, int p)

Constraints

  • is prime

Complexity

lcmPair

std::vector<std::tuple<int, int, int>> lcmPair(int n)

return all pair with

Complexity

DirichletProduct

give two function, , we define Dirichlet Product of as defined as

  • , then is call Mobius transform,
  • , then is call Mobius inverse transform, where is mobius function

Complexity

  • DirichletProduct:
  • Mobius transform:
  • Mobius inverse transform:

DirichletProduct Test

// docs/test/math/DirichletTest1.cpp
#include <bits/stdc++.h>
using LL = long long;
#include "../../cpplib/math/numberTheory.hpp"
using UL = unsigned long long;
std::mt19937_64 rnd64(std::chrono::steady_clock::now().time_since_epoch().count());

int main() {
  std::cin.tie(nullptr)->sync_with_stdio(false);
  int n = 1e5;
  std::vector<UL> a(n + 1), e(n + 1, 1), mu(n + 1);
  e[0] = 0;
  mu[1] = 1;
  for (int i = 1; i <= n; ++i) {
    for (int j = i * 2; j <= n; j += i) {
      mu[j] -= mu[i];
    }
  }
  for (int i = 1; i <= n; ++i) a[i] = rnd64();
  auto b = a;

  auto c = DirichletProduct(a, e, n);
  mobiousTran(a, n);
  for (int i = 0; i <= n; ++i) assert(a[i] == c[i]);

  c = DirichletProduct(c, mu, n);
  mobiousTranInv(a, n);
  for (int i = 0; i <= n; ++i) assert(a[i] == c[i]);
  for (int i = 0; i <= n; ++i) assert(a[i] == b[i]);


  c = DirichletRevProduct(a, e, n);
  mobiousRevTran(a, n);
  for (int i = 0; i <= n; ++i) assert(a[i] == c[i]);

  c = DirichletRevProduct(c, mu, n);
  mobiousRevTranInv(a, n);
  for (int i = 0; i <= n; ++i) assert(a[i] == c[i]);
  for (int i = 0; i <= n; ++i) assert(a[i] == b[i]);

  return 0;
}