Learning the notes polynomial basis

Simple polynomial Study Notes

Pre-knowledge and agreement

  • Polynomial multiplication, we can FFT/NTTsolve.
  • 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/NTTthe \ (\ mathcal O (n \ log n) \) in time to solve, but the two are not the same strengths and weaknesses.

FFTThe disadvantage of using a plurality of low precision, and use of the root, and large constant.

But NTTthe 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 多项式Lncalculation 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.

To be continue

Guess you like

Origin www.cnblogs.com/herself32-lyoi/p/11610362.html