数论-多项式模板
poly
以下内容极其不严谨,权当自己复习用。
FFT/NTT,牛顿迭代,求导,积分这些就不放模板了。
逆元
\[AB_t \equiv 1 \mod x^{2^t}
\]
\[(AB_t-1)^2 \equiv 0 \mod x^{2^{t+1}}
\]
\[A(2B_t-AB_t^2) \equiv 1 \mod x^{2^{t+1}}
\]
\[B_{t+1} \equiv B_t(2-AB_t)
\]
ln
\[\ln(A)=\int \frac{A'}{A}
\]
exp
\[B_t \equiv \exp A \mod x^{2^{t}}
\]
\[C=\ln B-A=0
\]
\[B_{t+1} \equiv B_{t}-\frac{C}{C'} \mod x^{2^{t+1}}
\]
\[B_{t+1} \equiv B_{t}-B_t(\ln B_t-A) \mod x^{2^{t+1}}
\]
\[B_{t+1} \equiv B_{t}(1-\ln B_t + A)
\]
带余除法
\(n\) 次幂级数 \(A\) , \(m\) 次幂级数 \(B\) 。
\[A \equiv BC+D \mod x^n
\]
\[A^r(x)=x^nA(\frac{1}{x})
\]
\[A^r \equiv B^rC^r \mod x^{n-m+1}
\]
复合逆
根据 Largrange's Formula :
\[F(G(x))=G(F(x))=x
\]
\[[x^n]H(G(x))=\frac{1}{n}[x^{n-1}]H'(x)(\frac{x}{F(x)})^n
\]
设 \(H(x)=x\) ,可以 \(O(n \log n)\) 求某一项的系数。
sqrt
虽然可以用 \(\ln\) 和 \(\exp\) 做,然而常数……
\[A \equiv B_t^2 \mod x^{2^t}
\]
\[(A+B_t^2)^2 - 4AB_t^2 \equiv 0 \mod x^{2^{t+1}}
\]
\[A \equiv \left(\frac{A+B_t^2}{2B_t}\right)^2 \mod x^{2^{t+1}}
\]
\[B_{t+1} \equiv \frac{A+B_t^2}{2B_t}
\]
\[B_{t+1} \equiv \frac{1}{2}(\frac{A}{B_t}+B_t)
\]
快速幂
注意 \(\ln\) 过程中进行了求导, \(0\) 次项被清零了,所以需要在 \(\exp\) 之前把 \(0\) 次项的数手动添加上。
QAQ
多点求值和多点插值就不放了,现推大概来得及。
Code
注意多项式乘法之后,需要在模意义下清零超出部分,即不能不清零,也不能多清零。
果然听起来很 zz 吧,但是这就是我调了 5h+ 的原因 Orz 。
#include <cstdio>
#include <ctype.h>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <ctime>
using namespace std;
char *p1, *p2, buf[1 << 20];
inline char gc()
{
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++;
}
template<typename T>
void rd(T &num)
{
char tt;
bool flag = 0;
while (!isdigit(tt = gc()) && tt != '-');
if (tt == '-')
num = 0, flag = 1;
else
num = tt - '0';
while (isdigit(tt = gc()))
num = num * 10 + tt - '0';
if (flag)
num = -num;
return;
}
const int P = 998244353;
const int _N = (1e5 + 100) * 16;
int L, N, M;
int Inv[_N], A[_N];
long long K;
int mul(int a, int b)
{
return 1ll * a * b % P;
}
int sub(int a, int b)
{
a -= b;
return a < 0 ? a + P : a;
}
int add(int a, int b)
{
a += b;
return a >= P ? a - P : a;
}
int mont(int a, int n)
{
int t = 1;
while (n) {
if (n & 1)
t = mul(t, a);
n >>= 1, a = mul(a, a);
}
return t;
}
void ntt(int *arr, int n, int opt)
{
static int r[_N];
int bit = -1, tn = n;
while (tn)
++bit, tn >>= 1;
for (int i = 0; i < (1 << bit); ++i)
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (bit - 1));
for (int i = 0; i < n; ++i)
if (i < r[i])
swap(arr[i], arr[r[i]]);
for (int l = 1; l < n; l <<= 1) {
int tmp = (P - 1) / (l << 1);
int wn = mont(3, opt == 1 ? tmp : P - 1 - tmp);
for (int i = 0; i < n; i += l << 1) {
int wi = 1;
for (int k = i; k < i + l; ++k) {
int t0 = arr[k], t1 = mul(wi, arr[k + l]);
arr[k] = add(t0, t1), arr[k + l] = sub(t0, t1);
wi = mul(wi, wn);
}
}
}
if (opt == -1) {
int tmp = mont(n, P - 2);
for (int i = 0; i < n; ++i)
arr[i] = mul(arr[i], tmp);
}
return;
}
void p_inv(int *a, int n)
{
static int b[_N], ta[_N];
b[0] = mont(a[0], P - 2);
for (int l = 2; l <= n; l <<= 1) {
for (int i = 0; i < l << 1; ++i) {
ta[i] = i < l ? a[i] : 0;
b[i] = i < l >> 1 ? b[i] : 0;
}
ntt(ta, l << 1, 1), ntt(b, l << 1, 1);
for (int i = 0; i < l << 1; ++i)
b[i] = mul(b[i], sub(2, mul(b[i], ta[i])));
ntt(b, l << 1, -1);
}
copy(b, b + n, a);
return;
}
void p_der(int *a, int n)
{
for (int i = 0; i < n - 1; ++i)
a[i] = mul(a[i + 1], i + 1);
a[n - 1] = 0;
return;
}
void p_int(int *a, int n)
{
for (int i = n - 1; i > 0; --i)
a[i] = mul(a[i - 1], Inv[i]);
a[0] = 0;
return;
}
void p_ln(int *a, int n)
{
static int ta[_N];
for (int i = 0; i < n << 1; ++i)
ta[i] = i < n ? a[i] : 0;
p_der(ta, n), p_inv(a, n);
ntt(a, n << 1, 1), ntt(ta, n << 1, 1);
for (int i = 0; i < n << 1; ++i)
a[i] = mul(a[i], ta[i]);
ntt(a, n << 1, -1);
fill(a + n, a + (n << 1), 0);
p_int(a, n);
return;
}
void p_exp(int *a, int n, int bas)
{
static int b[_N], tb[_N];
b[0] = bas; // note this
for (int l = 2; l <= n; l <<= 1) {
for (int i = 0; i < l << 1; ++i)
tb[i] = i < l >> 1 ? b[i] : 0;
p_ln(tb, l);
for (int i = 0; i < l << 1; ++i) {
tb[i] = i < l ? sub(a[i], tb[i]) : 0;
b[i] = i < l >> 1 ? b[i] : 0;
}
tb[0] = add(1, tb[0]);
ntt(b, l << 1, 1), ntt(tb, l << 1, 1);
for (int i = 0; i < l << 1; ++i)
b[i] = mul(b[i], tb[i]);
ntt(b, l << 1, -1);
}
copy(b, b + n, a);
return;
}
void p_sqrt(int *a, int n)
{
static int b[_N], tb[_N], ta[_N];
int iv = mont(2, P - 2);
b[0] = 1;
for (int l = 2; l <= n; l <<= 1) {
for (int i = 0; i < l << 1; ++i) {
tb[i] = i < l >> 1 ? b[i] : 0;
ta[i] = i < l ? a[i] : 0;
}
p_inv(tb, l);
ntt(ta, l << 1, 1), ntt(tb, l << 1, 1);
for (int i = 0; i < l << 1; ++i)
tb[i] = mul(ta[i], tb[i]);
ntt(tb, l << 1, -1);
for (int i = 0; i < l << 1; ++i)
b[i] = mul(iv, add(tb[i], b[i]));
}
copy(b, b + n, a);
return;
}
void p_mont(int *a, int n, long long k)
{
int t = mont(a[0], k % (P - 1));
p_ln(a, n);
for (int i = 0; i < n; ++i)
a[i] = mul(a[i], k % P);
p_exp(a, n, t);
return;
}
void iv_init(int n)
{
Inv[1] = 1;
for (int i = 2; i <= n; ++i)
Inv[i] = mul(P - P / i, Inv[P % i]);
return;
}
int main()
{
iv_init(2333);
return 0;
}