library

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

View the Project on GitHub maspypy/library

:heavy_check_mark: nt/sigma_0_sum.hpp

Depends on

Verified with

Code

#include "nt/convex_floor_sum.hpp"

// sum_[1,N] sigma_0(n)
template <typename T = u64>
T sigma_0_sum_small(u64 N) {
  u32 sq = sqrtl(N);
  T ANS = 0;
  for (u32 d = 1; d <= sq; ++d) { ANS += N / d; }
  return 2 * ANS - u64(sq) * sq;
}

// https://oeis.org/A006218
// sigma0(1)+...+sigma0(N) = sum floor(N/i)
template <typename T = u64>
T sigma_0_sum_large(u64 N) {
  u32 sq = sqrtl(N);
  auto above = [&](u128 x, u128 y) -> bool { return y * (sq - x) > N; };
  auto slope = [&](u128 x, u128 a, u128 b) -> bool {
    x = sq - x;
    return a * x * x <= N * b;
  };
  T ANS = convex_floor_sum<u64, T>(sq, above, slope);
  return 2 * ANS - u64(sq) * sq;
}

template <typename T = u64>
T sigma_0_sum(u64 N) {
  return (N < (1e14) ? sigma_0_sum_small<T>(N) : sigma_0_sum_large<T>(N));
}
#line 1 "nt/convex_floor_sum.hpp"

// f: 凸, 非負, 単調増加を仮定
// above(x,y) : y > f(x)
// slope(x,a,b) : f'(x) >= a/b
// return : sum_[0,N) floor(f(x))
// https://qoj.ac/contest/1195/problem/6188
template <typename U, typename ANS_TYPE, typename F1, typename F2>
ANS_TYPE convex_floor_sum(U N, F1 above, F2 slope) {
  if (N == 0) return 0;
  auto check = [&](U x, U y) -> bool { return x < N && above(x, y); };

  using T = ANS_TYPE;
  auto max_add = [&](auto f, U& a, U& b, U c, U d) -> void {
    auto dfs = [&](auto& dfs, U c, U d) -> void {
      if (!f(a + c, b + d)) return;
      a += c, b += d, dfs(dfs, c + c, d + d);
      if (f(a + c, b + d)) a += c, b += d;
    };
    dfs(dfs, c, d);
  };

  assert(!above(0, 0));
  U x = 0, y = 0;
  max_add([&](U x, U y) -> bool { return !above(x, y); }, x, y, 0, 1);
  ++y;
  T ANS = 2 * (y - 1); //  [0,1) x [1,y)

  auto add_ANS = [&](U& x, U& y, U a, U b) -> void {
    U x0 = x, y0 = y;
    max_add(check, x, y, a, b);
    U n = (x - x0) / a;
    //  (x0,y0) to (x,y)
    ANS += 2 * (y0 - 1) * (x - x0);
    ANS += (x - x0 + 1) * (y - y0 + 1) - (n + 1);
  };

  add_ANS(x, y, 1, 0);
  vc<tuple<U, U, U, U>> SBT;
  SBT.eb(1, 0, 0, 1);
  while (x < N - 1) {
    U a, b, c, d;
    tie(a, b, c, d) = SBT.back();
    if (!check(x + c, y + d)) {
      POP(SBT);
      continue;
    }
    auto f = [&](u64 a, u64 b) -> bool {
      if (x + a >= N) return 0;
      if (above(x + a, y + b)) return 0;
      if (slope(x + a, d, c)) return 0;
      return 1;
    };
    max_add(f, a, b, c, d);
    if (check(x + a + c, y + b + d)) {
      max_add([&](U a, U b) -> bool { return check(x + a, y + b); }, c, d, a, b);
      SBT.eb(a, b, c, d);
      continue;
    }
    add_ANS(x, y, c, d);
  }
  ANS /= T(2);
  return ANS;
}
#line 2 "nt/sigma_0_sum.hpp"

// sum_[1,N] sigma_0(n)
template <typename T = u64>
T sigma_0_sum_small(u64 N) {
  u32 sq = sqrtl(N);
  T ANS = 0;
  for (u32 d = 1; d <= sq; ++d) { ANS += N / d; }
  return 2 * ANS - u64(sq) * sq;
}

// https://oeis.org/A006218
// sigma0(1)+...+sigma0(N) = sum floor(N/i)
template <typename T = u64>
T sigma_0_sum_large(u64 N) {
  u32 sq = sqrtl(N);
  auto above = [&](u128 x, u128 y) -> bool { return y * (sq - x) > N; };
  auto slope = [&](u128 x, u128 a, u128 b) -> bool {
    x = sq - x;
    return a * x * x <= N * b;
  };
  T ANS = convex_floor_sum<u64, T>(sq, above, slope);
  return 2 * ANS - u64(sq) * sq;
}

template <typename T = u64>
T sigma_0_sum(u64 N) {
  return (N < (1e14) ? sigma_0_sum_small<T>(N) : sigma_0_sum_large<T>(N));
}
Back to top page