1. 程式人生 > >多項式對數函式學習筆記

多項式對數函式學習筆記

最近一直在學一些多項式的板子…

前置技能:多項式求逆

問題是對於 f ( x ) = ln g (

x ) f(x)=\ln g(x) ,已知 g ( x ) g(x)
,求 f ( x ) f(x)

用複合函式的求導法則,那麼原式轉換為: f

( x ) = g ( x ) g ( x ) f'(x)=\frac{g'(x)}{g(x)}

右邊那個東西可以用多項式求逆來做,求完以後積分就好了。

積分: f ( x ) d x = i = 1 n a i 1 i x i \int f(x)dx=\sum_{i = 1}^n\frac{a_{i - 1}}{i}x^i
求導: f ( x ) = i = 0 n 1 ( i + 1 ) a i + 1 x i f'(x)=\sum_{i=0}^{n-1}(i + 1)a_{i + 1}x^i

洛谷模板

Codes

#include <bits/stdc++.h>

using namespace std;

const int N = 1 << 18 | 1; 
const int mod = 998244353;

int g[N], invg[N], A[N], B[N], rev[N];

inline int add(int x, int y) { return (x += y) < mod ? x : x - mod; }

inline int qpow(int _, int __) {
    int ___ = 1; 
    for (; __; __ >>= 1, _ = 1ll * _ * _ % mod) 
        if (__ & 1) ___ = 1ll * ___ * _ % mod;
    return ___;
}

inline void NTT(int *a, int n, int fh) {
    for (int i = 0; i < n; ++ i) 
        if (i < rev[i]) swap(a[i], a[rev[i]]);
    for (int limit = 2, wn; limit <= n; limit <<= 1) {
        wn = qpow(fh ^ 1 ? qpow(3, mod - 2) : 3, (mod - 1) / limit);
        for (int j = 0, w = 1; j < n; j += limit, w = 1) 
            for (int i = j; i < j + (limit >> 1); ++ i, w = 1ll * w * wn % mod) {
                int a1 = a[i], a2 = 1ll * a[i + (limit >> 1)] * w % mod; 
                a[i] = add(a1, a2), a[i + (limit >> 1)] = add(a1, mod - a2);
            }
    }
    if (fh ^ 1) for (int i = 0, inv = qpow(n, mod - 2); i < n; ++ i) 
        a[i] = 1ll * a[i] * inv % mod;
}

inline void Invpoly(int *a, int *b, int len) {
    if (len ^ 1) {
        Invpoly(a, b, len >> 1);
        int k = 0, limit = 1; 
        while (limit < len * 2) limit <<= 1, ++ k; 
        for (int i = 0; i < limit; ++ i) {
            A[i] = B[i] = 0;
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
        }
        for (int i = 0; i < len; ++ i) 
            A[i] = a[i], B[i] = b[i];
        NTT(A, limit, 1), NTT(B, limit, 1);
        for (int i = 0; i < limit; ++ i) 
            A[i] = 1ll * A[i] * B[i] % mod * B[i] % mod;
        NTT(A, limit, -1);
        for (int i = 0; i < len; ++ i) 
            b[i] = add(b[i], add(b[i], mod - A[i]));
    }
    else b[0] = qpow(a[0], mod - 2);
}

inline void Derpoly(int *a, int len) {
    for (int i = 0; i < len - 1; ++ i) 
        a[i] = 1ll * (i + 1) * (a[i + 1]) % mod;
    a[len - 1] = 0;
}

inline void Intpoly(int *a, int len) {
    for (int i = len - 1; i; -- i) 
        a[i] = 1ll * a[i - 1] * qpow(i, mod - 2) % mod;
    a[0] = 0;
}

int main() {
#ifdef ylsakioi
    freopen("4725.in", "r", stdin);
    freopen("4725.out", "w", stdout);
#endif

    int limit = 1, k = 0, n; 
    scanf("%d", &n);
    while (limit < n * 2) limit <<= 1, ++ k;
    for (int i = 0; i < n; ++ i) 
        scanf("%d", &g[i]);
    Invpoly(g, invg, limit >> 1);
    Derpoly(g, limit >> 1);
    for (int i = 0; i < limit; ++ i) 
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
    NTT(g, limit, 1), NTT(invg, limit, 1);
    for (int i = 0; i < limit; ++ i) 
        g[i] = 1ll * g[i] * invg[i] % mod;
    NTT(g, limit, -1);
    Intpoly(g, limit);
    for (int i = 0; i < n; ++ i) 
        printf("%d ", g[i]);

    return 0;
}