Skip to content

Commit 50b109c

Browse files
committed
Dirichlet mul / div on floors
1 parent 187c1b7 commit 50b109c

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#ifndef CP_ALGO_NUMBER_THEORY_DIRICHLET_HPP
2+
#define CP_ALGO_NUMBER_THEORY_DIRICHLET_HPP
3+
#include <numeric>
4+
#include <cstdint>
5+
#include <vector>
6+
#include <cmath>
7+
namespace cp_algo::math {
8+
auto floor_stats(int64_t n) {
9+
auto rt_n = int(sqrtl(n));
10+
return std::pair{rt_n, 2 * rt_n - (n / rt_n == rt_n)};
11+
}
12+
13+
struct interval {
14+
int lo, hi;
15+
};
16+
17+
void exec_on_blocks(int64_t n, auto &&callback) {
18+
auto [rt_n, num_floors] = floor_stats(n);
19+
20+
auto to_ord = [&](int64_t k) {
21+
return k <= rt_n ? int(k) : num_floors - int(n / k) + 1;
22+
};
23+
24+
callback({1, 1}, {1, 1}, {1, num_floors});
25+
26+
for (int k = 2; k <= num_floors; ++k) {
27+
if(k > rt_n) {
28+
int z = num_floors - k + 1;
29+
for (int x = 2; ; x++) {
30+
int y_lo_ord = std::max(x, z) + 1;
31+
int y_hi_ord = to_ord(n / (x * z));
32+
if (y_hi_ord < y_lo_ord) break;
33+
callback({x, x}, {y_lo_ord, y_hi_ord}, {k, k});
34+
callback({y_lo_ord, y_hi_ord}, {x, x}, {k, k});
35+
}
36+
}
37+
38+
callback({1, 1}, {k, k}, {k, num_floors});
39+
callback({k, k}, {1, 1}, {k, num_floors});
40+
41+
if(k <= rt_n) {
42+
int x = k;
43+
for (int y = 2; y < k; ++y) {
44+
int z_lo_ord = to_ord(1LL * x * y);
45+
int z_hi_ord = to_ord(n / x);
46+
if (z_hi_ord < z_lo_ord) break;
47+
callback({x, x}, {y, y}, {z_lo_ord, z_hi_ord});
48+
callback({y, y}, {x, x}, {z_lo_ord, z_hi_ord});
49+
}
50+
int z_lo_ord = to_ord(1LL * x * x);
51+
callback({x, x}, {x, x}, {z_lo_ord, num_floors});
52+
}
53+
}
54+
}
55+
56+
auto Dirichlet_mul(auto &&F, auto &&G, int64_t n) {
57+
auto m = size(F);
58+
std::decay_t<decltype(F)> H(m+1);
59+
exec_on_blocks(n, [&](interval x, interval y, interval z) {
60+
auto sum_x = F[x.hi] - F[x.lo - 1];
61+
auto sum_y = G[y.hi] - G[y.lo - 1];
62+
auto t = sum_x * sum_y;
63+
H[z.lo] += t;
64+
H[z.hi + 1] -= t;
65+
});
66+
std::partial_sum(begin(H), end(H), begin(H));
67+
H.pop_back();
68+
return H;
69+
}
70+
71+
auto Dirichlet_div(auto &&H, auto &&G, int64_t n) {
72+
H.push_back(0);
73+
std::adjacent_difference(begin(H), end(H), begin(H));
74+
auto m = size(G);
75+
std::decay_t<decltype(G)> F(m);
76+
std::vector<bool> assigned(m);
77+
exec_on_blocks(n, [&](interval x, interval y, interval z) {
78+
auto sum_y = G[y.hi] - G[y.lo - 1];
79+
if (!assigned[x.hi]) {
80+
F[x.hi] = F[x.lo - 1] + H[z.lo] / sum_y;
81+
assigned[x.hi] = true;
82+
}
83+
auto sum_x = F[x.hi] - F[x.lo - 1];
84+
auto t = sum_y * sum_x;
85+
H[z.lo] -= t;
86+
H[z.hi + 1] += t;
87+
});
88+
return F;
89+
}
90+
91+
}
92+
#endif // CP_ALGO_NUMBER_THEORY_DIRICHLET_HPP
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// @brief Dirichlet Inverse and Prefix Sums
2+
#define PROBLEM "https://judge.yosupo.jp/problem/dirichlet_inverse_and_prefix_sums"
3+
4+
#include "cp-algo/number_theory/modint.hpp"
5+
#include "cp-algo/number_theory/dirichlet.hpp"
6+
#include <bits/stdc++.h>
7+
8+
using namespace std;
9+
using namespace cp_algo::math;
10+
using base = modint<998244353>;
11+
12+
void solve() {
13+
int64_t n;
14+
cin >> n;
15+
auto [_, m] = floor_stats(n);
16+
vector<base> H(m+1), G(m+1);
17+
for (int i = 1; i <= m; ++i) {
18+
cin >> G[i];
19+
}
20+
for (int i = 1; i <= m; ++i) {
21+
H[i] = 1;
22+
}
23+
auto F = Dirichlet_div(H, G, n);
24+
for (int i = 1; i <= m; ++i) {
25+
cout << F[i] << " \n"[i == m];
26+
}
27+
}
28+
29+
signed main() {
30+
//freopen("input.txt", "r", stdin);
31+
ios::sync_with_stdio(0);
32+
cin.tie(0);
33+
int t = 1;
34+
cin >> t;
35+
while(t--) {
36+
solve();
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// @brief Dirichlet Convolution and Prefix Sums
2+
#define PROBLEM "https://judge.yosupo.jp/problem/dirichlet_convolution_and_prefix_sums"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include "cp-algo/number_theory/modint.hpp"
5+
#include "cp-algo/number_theory/dirichlet.hpp"
6+
#include <bits/stdc++.h>
7+
8+
using namespace std;
9+
using namespace cp_algo::math;
10+
using base = modint<998244353>;
11+
12+
void solve() {
13+
int64_t n;
14+
cin >> n;
15+
auto [_, m] = floor_stats(n);
16+
vector<base> F(m+1), G(m+1);
17+
for (int i = 1; i <= m; ++i) {
18+
cin >> F[i];
19+
}
20+
for (int i = 1; i <= m; ++i) {
21+
cin >> G[i];
22+
}
23+
auto H = Dirichlet_mul(F, G, n);
24+
for (int i = 1; i <= m; ++i) {
25+
cout << H[i] << " \n"[i == m];
26+
}
27+
}
28+
29+
signed main() {
30+
//freopen("input.txt", "r", stdin);
31+
ios::sync_with_stdio(0);
32+
cin.tie(0);
33+
int t = 1;
34+
cin >> t;
35+
while(t--) {
36+
solve();
37+
}
38+
}

0 commit comments

Comments
 (0)