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>
77namespace 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