Simple polynomial Study Notes
Pre-knowledge and agreement
- Polynomial multiplication, we can
FFT/NTT
solve. - Simple derivation / calculus (
Simple mean if not to say it will not own the learned) - \ ([P] \) represents Iverson bracket, when the \ (P \) is true when the value of the expression \ (. 1 \) , \ (P \) is false expression is \ (0 \ )
- \ (\ Gamma \) represents the factorial function
- \ (f ^ {(n) } \) represents the function \ (f (x) \) a \ (n-\) derivative function
Polynomial multiplication
We can use FFT/NTT
the \ (\ mathcal O (n \ log n) \) in time to solve, but the two are not the same strengths and weaknesses.
FFT
The disadvantage of using a plurality of low precision, and use of the root, and large constant.
But NTT
the disadvantage that to be used (as in the case of the more primitive roots modulo special case \ (998,244,353 \) , etc.).
Code
inline void NTT(int *f, int type) {
for(int i = 0; i < n; ++i) if(i < rev[i]) std::swap(f[i], f[rev[i]]);
for(int i = 1; i < n; i <<= 1) {
int tk = quick_power(3, (mod - 1) / (i << 1));
for(int j = 0; j < n; j += (i << 1)) {
int t = 1, x, y;
for(int k = 0; k < i; ++k, t = 1ll * t * tk % mod) {
x = f[j + k], y = 1ll * t * f[j + k + i] % mod;
f[j + k] = (x + y) % mod; f[j + k + i] = (x - y + mod) % mod;
}
}
}
if(type == 1) return ;
int inv = quick_power(n, mod - 2);
std::reverse(f + 1, f + n);
for(int i = 0; i < n; ++i) f[i] = 1ll * f[i] * inv % mod;
}
Taylor polynomial expansion
If the function \ (f (x) \) in \ (x_0 \) is present at \ (n-\) order derivative, then the definition of \ (f (x) \) in \ (x = x_0 \) at the \ (\ RM taylor \) expansions:
\[f(x) = \sum_{i=0}^n \frac {f^{(n)}(x_0)}{\Gamma(i)} (x - x_0)^i + R_n(x)\]
Where \ (R_n (x) \) represents the Lagrange remainder, namely \ ((x - x_0) ^ n \) higher order infinitesimal.
An example: \ (. 1 + E = X ^ \ FRAC {X} {\ the Gamma (. 1)} + \ ^ X FRAC {2} {\ the Gamma (2)} + \ cdots \)
Polynomial Newton iteration
Newton iteration can be used to find the zero function, and a polynomial zero Newton iteration may find a polynomial function.
I.e., for a polynomial \ (F. (X) \) , find a polynomial \ (G_k (x) \) satisfies \ (F (G_k (x) ) \ equiv 0 \ pmod {2 ^ k} \)
Suppose we have calculated the \ (K-G_ {}. 1 (X) \) , consider how the push \ (G_k (x) \)
We \ (F (G_k (x) ) \) in \ (x = G_ {k- 1} (x) \) for the \ (\ rm Taylor \) to expand, can be obtained:
\[F(G_k(x)) = F(G_{k-1}(x)) + \frac {F'(G_{k-1}(x))}{\Gamma(1)} (G_k(x) - G_{k-1}(x))\]
Simplification, transposition was:
\[G_k(x) = G_{k-1}(x) - \frac {F(G_{k-1}(x))}{F'(G_{k-1}(x))}\]
Inverse polynomial
Known \ (F. (X) \) , seeking \ (G (x) \) satisfies \ (F (x) G ( x) \ equiv 1 \ pmod {x ^ n} \)
And push Newton iteration equation, we assume have obtained a \ (G_0 (x) \) is satisfied:
\[F(x)G_0(x) \equiv 1 \pmod{x^{\lfloor \frac {2}{n}\rfloor}}\]
Conditions can be obtained from the subject:
\[F(x)G(x) \equiv 1 \pmod{x^{\lfloor \frac {2}{n}\rfloor}}\]
Upper and lower two subtraction device can be obtained:
\[F(x)G_0(x) - F(x)G(x) \equiv 0 \pmod{x^{\lfloor \frac {2}{n}\rfloor}}\]
Congruence on both sides at the same time divided by \ (F (x) \) can be obtained:
\[G_0(x) - G(x) \equiv 0 \pmod{x^{\lfloor \frac {2}{n}\rfloor}}\]
More than twice the square of the same type can be obtained:
\[G_0(x)^2 - 2G(x)G_0(x) + G(x)^2 \equiv 0 \pmod{x^n}\]
By the subject condition, while at the same time on both sides of the congruence multiply \ (F (x) \) was:
\[F(x)G_0(x)^2 - 2G_0(x) + G(x) \equiv 0 \pmod{x^n}\]
The formula transposition, available:
\[G(x) = 2G_0(x) - F(x)G_0(x)^2 \equiv 0 \pmod{x^n}\]
Recursive solution can be.
Code
inline void PolyInv(int *f, int *g, int len) {
if(len == 1) {g[0] = quick_power(f[0], mod - 2); return ;}
PolyInv(f, g, (len + 1) >> 1);
n = 1, m = 0;
while(n < (len << 1)) {n <<= 1; ++m;}
for(int i = 1; i < n; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (m - 1));
for(int i = 0; i < len; ++i) c[i] = f[i];
for(int i = len; i < n; ++i) c[i] = 0;
NTT(c, 1); NTT(g, 1);
for(int i = 0; i < n; ++i) g[i] = 1ll * (2 - 1ll * c[i] * g[i] % mod + mod) % mod * g[i] % mod;
NTT(g, -1);
for(int i = len; i < n; ++i) g[i] = 0;
}
Polynomial derivation
Nothing to say it, given the formula:
\[x^{a^{\prime}} = ax^{a-1}\]
Code
inline void PolyDer(int *f, int *g, int len) {
for(int i = 1; i < len; ++i) g[i - 1] = 1ll * i * f[i] % mod;
g[len - 1] = 0;
}
Polynomials
According to Newton - Leibniz formula:
\[\int x^a {\rm d}x = \frac {1}{a+1} x^{a+1}\]
Code
inline void PolyInt(int *f, int *g, int len) {
for(int i = 1; i < len; ++i) g[i] = 1ll * f[i - 1] * quick_power(i, mod - 2) % mod;
g[0] = 0;
}
Polynomial logarithmic function
That polynomial evaluation \ (\ ln \)
Known \ (F. (X) \) , seeking \ (G (x) \) satisfies \ (G (x) \ equiv \ ln F (x) \ pmod {x ^ n} \)
Set function \ (H (the X-) = \ the X-LN \) , then that is the right congruence \ (H (F (the X-)) \) .
Considering the derivative of Formula it with both sides, can be obtained:
\[G'(x) \equiv H'(x) \pmod{x^n}\]
which is:
\[G'(x) \equiv \frac{F'(x)}{F(x)} \pmod{x^n}\]
Then we put \ (F (x) \) to pray for guidance, and then seek a reverse, then ask about the convolution of two polynomials obtained.
So that we get is \ (G '(the X-) \) , and then he went back to the plot.
Code
inline void PolyLn(int *f, int *g, int len) {
PolyDer(f, a, len); PolyInv(f, b, len);
n = 1; m = 0;
while(n < (len << 1)) {n <<= 1; ++m;}
for(int i = 1; i < n; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (m - 1));
NTT(a, 1); NTT(b, 1);
for(int i = 0; i < n; ++i) a[i] = 1ll * a[i] * b[i] % mod;
NTT(a, -1); PolyInt(a, g, len);
}
Polynomial exponential function
That polynomial evaluation \ (\ rm exp \)
Known \ (F. (X) \) , seeking \ (G (x) \) satisfies \ (G (X) \ equiv \ exp (F. (X)) \ n-PMOD {X} ^ \) .
At the same time consider taking the natural logarithm of both sides of congruence:
\[\ln G(x) \equiv F(x) \pmod{x^n}\]
Transposition, available:
\[\ln G(x) - F(x) \equiv 0 \pmod{x^n}\]
This equation will be set into the 多项式牛顿迭代
available:
\[G(x) \equiv G_0(x) - \frac {\ln G_0(x) - F(x)}{\frac {1}{G_0(x)}}\]
Simplification can be obtained:
\[G(x) \equiv G_0(x) - (\ln G_0(x) - F(x)) \times G_0(x) \pmod {x^n}\]
\[G(x) \equiv G_0(x) \times (1 - \ln G_0(x) + F(x)) \pmod {x^n}\]
+ Recursive 多项式Ln
calculation can.
Code
inline void PolyExp(int *f, int *g, int len) {
if(len == 1) {g[0] = 1; return ;}
PolyExp(f, g, (len + 1) >> 1);
n = 1; m = 0;
while(n < (len << 1)) {n <<= 1; ++m;}
for(int i = 1; i < n; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (m - 1));
for(int i = 0; i < (len << 1); ++i) d[i] = e[i] = 0;
PolyLn(g, d, len);
for(int i = 0; i < len; ++i) e[i] = f[i];
NTT(g, 1); NTT(d, 1); NTT(e, 1);
for(int i = 0; i < n; ++i) g[i] = (1ll - d[i] + e[i] + mod) * g[i] % mod;
NTT(g, -1);
for(int i = len; i < n; ++i) g[i] = 0;
}
Fast power polynomial
Known \ (F. (X) \) , seeking \ (G (x) \) satisfies \ (G (x) \ equiv F (x) ^ k \ pmod {x ^ n} \)
First, we should be in junior high school had such a formula:
\[\log_a b^k = k \log_a b\]
This polynomial equation is also true,
So we just need to \ (F (x) \) seeking a \ (\ LN \) , and then it multiplied by \ (k \) , and finally \ (\ exp \) to go back to.
Code
inline void PolyPow(int *f, int *g, int k, int len){
PolyLn(f, h, len);
for(int i = 0; i < len; ++i) h[i] = 1ll * h[i] * k % mod;
PolyExp(h, g, len);
for(int i = 0; i < len; ++i) h[i] = 0;
}
Open polynomial root
Known \ (F. (X) \) , seeking \ (G (x) \) satisfies \ (G (x) ^ 2 \ equiv F (x) \ pmod {x ^ n} \)
And inverse polynomial similar to the use of that conclusion, we get:
\[2 \ln G(x) \equiv \ln F(x) \pmod{x^n}\]
Then we put \ (F (x) \) seeking a \ (\ LN \) , then its coefficients are multiplied by \ (2 \) is inverse, and finally \ (\ exp \) to go back to.
Code
inline void PolySqr(int *f, int *g, int len) {
PolyLn(f, l, len);
int invt = quick_power(2, (mod - 2));
for(int i = 0; i < len; ++i) l[i] = 1ll * l[i] * invt % mod;
PolyExp(l, g, len);
for(int i = 0; i < len; ++i) l[i] = 0;
}
Update log & references
- 2019/9/27, update to the inverse polynomial
- 2019/9/28 update to open polynomial root
- 2019/9/28, To do polynomial division & modulus
The author is completely follow Venus and M-sea polynomial uncle school, so there are many references to this article from their blog.
Thanks again for these two blog gives this chicken dish polynomial help in learning in!
Abstract from NaCly_Fish Luogu personal space.