polyALL.hpp
The size: should be less than , since module used in NTT are only multiples of .
poly.hpp
support almost every algorithm involved polynomial and the module number can be any prime number.
how to choose
There are PolyNTT
, PolyFFT
, PolyFFTDynamic
, PolyMFT
provided to suit for different module .
- PolyMFT:
- PolyFFTDynamic: else if is uncertain.
- PolyNTT: else if is fixed NTT-friendly, such as or
PolyS
instead - PolyFFT: else
PolyOrigin
for testing.
polyS.hpp
PolyS.hpp
is a simple and small version of Poly. It contains basic operators: +, -, *, /
, log, exp, sqrt, and multi-evaluation for fiexed mod = 998244353.
You may change
NTTS::M = 998244353
to other NTT-friendly prime number(and primitive rootNTTS::g = 3
).
Arbitrary module
However should be bigger than the size since some function need to assmue invertible in
Two ways to support it.
- FFT based: you should check if the precision sufficient
- NTT based: use 3 or 4 or more NTT-friendly modules, are then use Chinese remainder theorem
we choose M0 = 595591169, M1 = 645922817, M2 = 897581057, M3 = 998244353
in PolyMFT using following sageMath code:
ans = []
for i in range(23, 28):
for j in range(1, 1000, 2):
if(j * 2 ^i + 1 < 2^30 and is_prime(j*2^i+1) and primitive_root(j*2^i+1) == 3):
ans.append(j*2^i+1)
for i in sorted(ans):
print(i, "\t = 1 + ", factor(i-1))
# output:
# 167772161 = 1 + 2^25 * 5
# 469762049 = 1 + 2^26 * 7
# 595591169 = 1 + 2^23 * 71
# 645922817 = 1 + 2^23 * 7 * 11
# 897581057 = 1 + 2^23 * 107
# 998244353 = 1 + 2^23 * 7 * 17
Method
- elementary:
+, -, *, /, %, +=, -=, *=, /=, %=, -(negative)
, inv, mulXn, modXn, divXn. - fundamental: powModPoly, inner, derivation, integral, log, exp, sqrt, mulT, evals, Lagrange, linearRecursion, prod, stirling number(stirling1row, stirling1col, stirling2row, stirling2col)
- mixed: sin, cos, asin, atan, compose, composeInv, toFallingPowForm, fromFallingPowForm, valToVal
- prefixPowSum:
- sumFraction:
As an application, we compute and (introduced by min_25) in poly.hpp
Example
#include <bits/stdc++.h>
using LL = long long;
#include "cpplib/math.hpp"
template<typename T>
void debug(std::vector<T> a){
for (auto& i : a) std::cout << i << ' ';
std::cout << std::endl;
}
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
std::vector<int> a{1, 2, 3, 4};
std::vector<int> b{1, 2, 3};
PolyS A1(a), B1(b);
auto c1 = (A1 * B1).a;
debug(c1);
using modM = MInt<998244353>;
PolyNTT A2(trans<modM>(a)), B2(trans<modM>(b));
auto c2 = (A2 * B2).a;
debug(c2);
// you must setMod before using it
ModInt::setMod(998244353);
PolyFFTDynamic A3(trans<ModInt>(a)), B3(trans<ModInt>(b));
auto c3 = (A3 * B3).a;
debug(c3);
ModLL::setMod(998244353);
PolyMFT A4(trans<ModLL>(a)), B4(trans<ModLL>(b));
auto c4 = (A4 * B4).a;
debug(c4);
return 0;
}