Skip to content

Commit 4c9e0c2

Browse files
committed
inplace Dirichlet division
1 parent 509fb52 commit 4c9e0c2

File tree

1 file changed

+25
-12
lines changed

1 file changed

+25
-12
lines changed

cp-algo/number_theory/dirichlet.hpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#ifndef CP_ALGO_NUMBER_THEORY_DIRICHLET_HPP
22
#define CP_ALGO_NUMBER_THEORY_DIRICHLET_HPP
3-
#include <numeric>
3+
#include <algorithm>
44
#include <cstdint>
5-
#include <vector>
5+
#include <ranges>
66
#include <cmath>
77
namespace cp_algo::math {
88
auto floor_stats(int64_t n) {
@@ -16,8 +16,10 @@ namespace cp_algo::math {
1616
};
1717

1818
// callback(k, prefix) such that:
19-
// (F * G)[k] = prefix + (F[k] - F[k-1]) * G[1] + (G[k] - G[k-1]) * F[1]
19+
// (F * G)[k] = prefix + (F[k] - F[k-1]) * G[1] + (G[k] - G[k-1]) * F[1]
2020
// Uses H as a buffer for (F * G)[k], then overrides with callback results
21+
enum exec_mode { standard, reverse };
22+
template<exec_mode mode = standard>
2123
void exec_on_blocks(int64_t n, auto &H, auto const& F, auto const& G, auto &&callback) {
2224
auto [rt_n, num_floors] = floor_stats(n);
2325

@@ -27,7 +29,12 @@ namespace cp_algo::math {
2729

2830
auto call = [&](interval x, interval y, interval z) {
2931
auto sum_x = F[x.hi] - F[x.lo - 1];
30-
auto sum_y = G[y.hi] - G[y.lo - 1];
32+
decltype(sum_x) sum_y;
33+
if constexpr (mode == standard) {
34+
sum_y = G[y.hi] - G[y.lo - 1];
35+
} else {
36+
sum_y = G[y.lo - 1] - G[y.hi];
37+
}
3138
auto t = sum_x * sum_y;
3239
H[z.lo] += t;
3340
if (z.hi < num_floors) {
@@ -66,26 +73,32 @@ namespace cp_algo::math {
6673
}
6774
}
6875

69-
auto Dirichlet_mul(auto &&F, auto &&G, int64_t n) {
76+
auto Dirichlet_mul(auto const& F, auto const& G, int64_t n) {
7077
auto m = size(F);
7178
std::decay_t<decltype(F)> H(m);
7279
H[1] = F[1] * G[1];
7380
exec_on_blocks(n, H, F, G, [&](auto k, auto prefix) {
74-
return prefix + (F[k] - F[k - 1]) * G[1] + (G[k] - G[k - 1]) * F[1];
81+
return prefix + (F[k] - F[k-1]) * G[1] + (G[k] - G[k-1]) * F[1];
7582
});
7683
return H;
7784
}
7885

79-
auto Dirichlet_div(auto &&H, auto &&G, int64_t n) {
86+
void Dirichlet_div_inplace(auto &H, auto const& G, int64_t n) {
8087
auto m = size(G);
81-
std::decay_t<decltype(G)> F(m);
8288
auto Gi = G[1].inv();
83-
F[1] = Gi * H[1];
84-
exec_on_blocks(n, F, F, G, [&](auto k, auto prefix) {
85-
return F[k-1] + (Gi * (H[k] - prefix - (G[k] - G[k-1]) * F[1]));
89+
H[0] -= H[0];
90+
adjacent_difference(begin(H), end(H), begin(H));
91+
H[1] *= Gi;
92+
exec_on_blocks<reverse>(n, H, H, G, [&](auto k, auto) {
93+
return (Gi * (H[k] - (G[k] - G[k-1]) * H[1])) + H[k-1];
8694
});
87-
return F;
8895
}
8996

97+
auto Dirichlet_div(auto const& H, auto const& G, int64_t n) {
98+
auto m = size(G);
99+
auto F = H | std::views::take(m) | std::ranges::to<std::decay_t<decltype(G)>>();
100+
Dirichlet_div_inplace(F, G, n);
101+
return F;
102+
}
90103
}
91104
#endif // CP_ALGO_NUMBER_THEORY_DIRICHLET_HPP

0 commit comments

Comments
 (0)