Skip to content

Commit 93faa48

Browse files
committed
added NTT convolution.
1 parent 29d496a commit 93faa48

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

src/alfred/math/conv.hpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#ifndef AFMT_CONV
2+
#define AFMT_CONV
3+
4+
#include "mod-int.hpp"
5+
#include <vector>
6+
7+
namespace detail {
8+
template <class mint>
9+
void NTT(std::vector<mint> &f, std::vector<int> &r, int lim, int flag) {
10+
const int mod = mint::mod();
11+
mint gmod = findPrimitiveRoot<mint>();
12+
for (int i = 0; i < lim; i++) {
13+
if (i < r[i]) std::swap(f[i], f[r[i]]);
14+
}
15+
mint invg = gmod.inv(), tmp;
16+
mint v = flag > 0 ? gmod : invg;
17+
for (int k = 1; k < lim; k <<= 1) {
18+
const int len = k << 1;
19+
mint gn = v.pow((mod - 1) / len), g = 1;
20+
for (int i = 0; i < lim; i += len, g = 1) {
21+
for (int j = 0; j < k; j++, g *= gn) {
22+
tmp = f[i + j + k] * g;
23+
f[i + j + k] = f[i + j] - tmp;
24+
f[i + j] += tmp;
25+
}
26+
}
27+
}
28+
if (flag == -1) {
29+
mint inv = mint(lim).inv();
30+
for (auto &x : f) x *= inv;
31+
}
32+
}
33+
}
34+
35+
// (*, +) convolution for modint
36+
template <uint32_t mod>
37+
inline std::vector<ModInt<mod>> add_conv(
38+
std::vector<ModInt<mod>> f,
39+
std::vector<ModInt<mod>> g
40+
) {
41+
int len = f.size() + g.size() - 1, lim;
42+
for (lim = 1; lim < len; lim <<= 1);
43+
f.resize(lim, 0), g.resize(lim, 0);
44+
45+
std::vector<int> rev(lim, 0);
46+
std::vector<ModInt<mod>> h(lim, 0);
47+
for (int i = 0; i < lim; i++) {
48+
rev[i] = rev[i >> 1] >> 1;
49+
if (i & 1) rev[i] |= lim >> 1;
50+
}
51+
detail::NTT(f, rev, lim, 1);
52+
detail::NTT(g, rev, lim, 1);
53+
for (int i = 0; i < lim; i++) {
54+
h[i] = f[i] * g[i];
55+
}
56+
detail::NTT(h, rev, lim, -1);
57+
return h.resize(len), h;
58+
}
59+
60+
/*
61+
// (*, +) convolution for long long
62+
inline std::vector<long long> add_convll(
63+
std::vector<long long> f, std::vector<long long> g
64+
) {
65+
std::vector<ModInt<998244353>> f1(f.begin(), f.end());
66+
std::vector<ModInt<998244353>> g1(g.begin(), g.end());
67+
std::vector<ModInt<998244353>> h1 = add_conv(f1, g1);
68+
69+
std::vector<ModInt<469762049>> f2(f.begin(), f.end());
70+
std::vector<ModInt<469762049>> g2(g.begin(), g.end());
71+
std::vector<ModInt<469762049>> h2 = add_conv(f2, g2);
72+
73+
std::vector<ModInt<1004535809>> f3(f.begin(), f.end());
74+
std::vector<ModInt<1004535809>> g3(g.begin(), g.end());
75+
std::vector<ModInt<1004535809>> h3 = add_conv(f3, g3);
76+
77+
std::vector<T> res(h1.size());
78+
}
79+
*/
80+
81+
#endif

src/alfred/math/mod-int.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ void __print(m107 M) {
171171
std::cerr << M;
172172
}
173173

174+
template <class mint>
175+
constexpr mint findPrimitiveRoot(void) {
176+
mint i = 2;
177+
const int P = mint::mod();
178+
int k = __builtin_ctz(P - 1);
179+
while (true) {
180+
if (i.pow((P - 1) / 2) != 1) {
181+
break;
182+
}
183+
i += 1;
184+
}
185+
return i.pow((P - 1) >> k);
186+
}
187+
174188
using dint = DynamicModInt;
175189

176190
#endif // AFMT_MOD_INT

0 commit comments

Comments
 (0)