floor_sum.hpp¶
计算任意整数区间上的整除下取整之和,支持系数为负。
\[
\displaystyle F=\sum_{i=L}^{R-1}\left\lfloor\frac{ai+b}{m}\right\rfloor
\]
Complexity: Time: O(log m). Space: O(1).
AC 记录:sum_of_floor_of_linear。
Implementation¶
当前头文件,省略 include guard;依赖见 #include。
/// @complexity Time: O(log m).
/// Space: O(1).
#include <cassert>
#include <cstdint>
#include <utility>
namespace noya {
using floor_sum_result = __int128_t;
namespace floor_sum_internal {
inline floor_sum_result floor_div(floor_sum_result val, floor_sum_result mod) {
floor_sum_result quo = val / mod;
if (val % mod < 0) {
quo--;
}
return quo;
}
} // namespace floor_sum_internal
/// @brief Sum floor((a*i+b)/mod) over i in [l, r), allowing signed
/// l, a, and b; the exact result must fit in signed 128 bits.
inline floor_sum_result floor_sum_range(std::int64_t l, std::int64_t r,
std::int64_t a, std::int64_t b,
std::int64_t mod) {
assert(l <= r && mod > 0);
using floor_sum_internal::floor_div;
floor_sum_result n = floor_sum_result(r) - l;
floor_sum_result m = mod;
floor_sum_result k = a;
floor_sum_result ntr = floor_sum_result(a) * l + b;
floor_sum_result res = 0;
floor_sum_result sq = floor_div(k, m);
k -= sq * m;
res += n * (n - 1) / 2 * sq;
floor_sum_result iq = floor_div(ntr, m);
ntr -= iq * m;
res += n * iq;
while (true) {
if (k >= m) {
res += n * (n - 1) / 2 * (k / m);
k %= m;
}
if (ntr >= m) {
res += n * (ntr / m);
ntr %= m;
}
floor_sum_result mx = k * n + ntr;
if (mx < m) {
break;
}
n = mx / m;
ntr = mx % m;
std::swap(m, k);
}
return res;
}
} // namespace noya
#ifndef NOYA_FLOOR_SUM_HPP
#define NOYA_FLOOR_SUM_HPP 1
/// @complexity Time: O(log m).
/// Space: O(1).
#include <cassert>
#include <cstdint>
#include <utility>
namespace noya {
using floor_sum_result = __int128_t;
namespace floor_sum_internal {
inline floor_sum_result floor_div(floor_sum_result val, floor_sum_result mod) {
floor_sum_result quo = val / mod;
if (val % mod < 0) {
quo--;
}
return quo;
}
} // namespace floor_sum_internal
/// @brief Sum floor((a*i+b)/mod) over i in [l, r), allowing signed
/// l, a, and b; the exact result must fit in signed 128 bits.
inline floor_sum_result floor_sum_range(std::int64_t l, std::int64_t r,
std::int64_t a, std::int64_t b,
std::int64_t mod) {
assert(l <= r && mod > 0);
using floor_sum_internal::floor_div;
floor_sum_result n = floor_sum_result(r) - l;
floor_sum_result m = mod;
floor_sum_result k = a;
floor_sum_result ntr = floor_sum_result(a) * l + b;
floor_sum_result res = 0;
floor_sum_result sq = floor_div(k, m);
k -= sq * m;
res += n * (n - 1) / 2 * sq;
floor_sum_result iq = floor_div(ntr, m);
ntr -= iq * m;
res += n * iq;
while (true) {
if (k >= m) {
res += n * (n - 1) / 2 * (k / m);
k %= m;
}
if (ntr >= m) {
res += n * (ntr / m);
ntr %= m;
}
floor_sum_result mx = k * n + ntr;
if (mx < m) {
break;
}
n = mx / m;
ntr = mx % m;
std::swap(m, k);
}
return res;
}
} // namespace noya
#endif // NOYA_FLOOR_SUM_HPP
#include <cassert>
#include <cstdint>
#include <utility>
/// @complexity Time: O(log m).
/// Space: O(1).
namespace noya {
using floor_sum_result = __int128_t;
namespace floor_sum_internal {
inline floor_sum_result floor_div(floor_sum_result val, floor_sum_result mod) {
floor_sum_result quo = val / mod;
if (val % mod < 0) {
quo--;
}
return quo;
}
} // namespace floor_sum_internal
/// @brief Sum floor((a*i+b)/mod) over i in [l, r), allowing signed
/// l, a, and b; the exact result must fit in signed 128 bits.
inline floor_sum_result floor_sum_range(std::int64_t l, std::int64_t r,
std::int64_t a, std::int64_t b,
std::int64_t mod) {
assert(l <= r && mod > 0);
using floor_sum_internal::floor_div;
floor_sum_result n = floor_sum_result(r) - l;
floor_sum_result m = mod;
floor_sum_result k = a;
floor_sum_result ntr = floor_sum_result(a) * l + b;
floor_sum_result res = 0;
floor_sum_result sq = floor_div(k, m);
k -= sq * m;
res += n * (n - 1) / 2 * sq;
floor_sum_result iq = floor_div(ntr, m);
ntr -= iq * m;
res += n * iq;
while (true) {
if (k >= m) {
res += n * (n - 1) / 2 * (k / m);
k %= m;
}
if (ntr >= m) {
res += n * (ntr / m);
ntr %= m;
}
floor_sum_result mx = k * n + ntr;
if (mx < m) {
break;
}
n = mx / m;
ntr = mx % m;
std::swap(m, k);
}
return res;
}
} // namespace noya