Luogu 4725 【模板】多项式对数函数

继续补全模板。

要求

$$g(x) = ln f(x)$$

两边求导,

$$g‘(x) = \frac{f‘(x)}{f(x)}$$

然后左转去把多项式求导和多项式求逆的模板复制过来,就可以计算出$g‘(x)$,接下来再对$g‘(x)$求不定积分即可。

虽然我也不是很会不定积分,但是这就是求导的逆过程,相当于把求完导之后的函数搞回去。

因为$(a_ix^i)‘ = ia_ix^{i - 1}$,所以反向算一下就好。

求导的时间复杂度是$O(n)$,积分的时间复杂度是$O(nlogn)$,总时间复杂度是$O(nlogn)$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N = 1 << 18;

int n;
ll f[N], g[N];

namespace Poly {
    const int L = 1 << 18;
    const ll P = 998244353LL;

    int lim, pos[L];
    ll f[L], g[L], h[L];

    inline ll fpow(ll x, ll y) {
        ll res = 1;
        for (x %= P; y > 0; y >>= 1) {
            if (y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }

    inline void prework(int len) {
        int l = 0;
        for (lim = 1; lim < len; lim <<= 1, ++l);
        for (int i = 0; i < lim; i++)
            pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
    }

    inline void ntt(ll *c, int opt) {
        for (int i = 0; i < lim; i++)
            if (i < pos[i]) swap(c[i], c[pos[i]]);
        for (int i = 1; i < lim; i <<= 1) {
            ll wn = fpow(3, (P - 1) / (i << 1));
            if (opt == -1) wn = fpow(wn, P - 2);
            for (int len = i << 1, j = 0; j < lim; j += len) {
                ll w = 1;
                for (int k = 0; k < i; k++, w = w * wn % P) {
                    ll x = c[j + k], y = w * c[j + k + i] % P;
                    c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
                }
            }
        }

        if (opt == -1) {
            ll inv = fpow(lim, P - 2);
            for (int i = 0; i < lim; i++) c[i] = c[i] * inv % P;
        }
    }

    void inv(ll *a, ll *b, int len) {
        if (len == 1) {
            b[0] = fpow(a[0], P - 2);
            return;
        }

        inv(a, b, (len + 1) >> 1);
        prework(len << 1);
        for (int i = 0; i < lim; i++) f[i] = g[i] = 0;
        for (int i = 0; i < len; i++) f[i] = a[i], g[i] = b[i];
        ntt(f, 1), ntt(g, 1);
        for (int i = 0; i < lim; i++)
            g[i] = g[i] * (2LL - g[i] * f[i] % P + P) % P;
        ntt(g, -1);

        for (int i = 0; i < len; i++) b[i] = g[i];
    }

    inline void direv(ll *c, int len) {
        for (int i = 0; i < len - 1; i++) c[i] = c[i + 1] * (i + 1) % P;
        c[len - 1] = 0;
    }

    inline void integ(ll *c, int len) {
        for (int i = len - 1; i > 0; i--) c[i] = c[i - 1] * fpow(i, P - 2) % P;
        c[0] = 0;
    }

    inline void ln(ll *a, ll *b, int len) {
        for (int i = 0; i < len; i++) h[i] = 0;
        inv(a, h, len);

/*        for (int i = 0; i < len; i++)
            printf("%lld%c", h[i], " \n"[i == n - 1]);    */

        for (int i = 0; i < len; i++) b[i] = a[i];
        direv(b, len);

/*        for (int i = 0; i < len; i++)
            printf("%lld%c", b[i], " \n"[i == n - 1]);    */

        prework(len << 1);
        ntt(h, 1), ntt(b, 1);
        for (int i = 0; i < lim; i++) b[i] = b[i] * h[i] % P;
        ntt(b, -1);

/*        for (int i = 0; i < len; i++)
            printf("%lld%c", b[i], " \n"[i == n - 1]);    */

        integ(b, len);
    }

};

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for (; ch > ‘9‘|| ch < ‘0‘; ch = getchar())
        if (ch == ‘-‘) op = -1;
    for (; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

int main() {
    read(n);
    for (int i = 0; i < n; i++) read(f[i]);
    Poly :: ln(f, g, n);
    for (int i = 0; i < n; i++)
        printf("%lld%c", g[i], " \n"[i == n - 1]);
    return 0;
}

原文地址:https://www.cnblogs.com/CzxingcHen/p/10277129.html

时间: 2024-10-07 18:24:05

Luogu 4725 【模板】多项式对数函数的相关文章

[luogu P3384] [模板]树链剖分

[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<ctime> #include<queue> #inc

luogu 4725 【模板】多项式对数函数(多项式 ln)

Code: #include <cstdio> #include <string> #include <algorithm> #include <cstring> #include <vector> #define setIO(s) freopen(s".in","r",stdin) typedef long long ll; const int maxn=2100005; const ll mod=998

luogu P4725 多项式对数函数 (模板题、FFT、多项式求逆、求导和积分)

手动博客搬家: 本文发表于20181125 13:25:03, 原地址https://blog.csdn.net/suncongbo/article/details/84487306 题目链接: https://www.luogu.org/problemnew/show/P4725 题目大意: 给定一个\(n\)次多项式\(A(x)\), 求一个\(n\)次多项式\(B(x)\)满足\(B(x)\equiv \ln A(x) (\mod x^n)\) 题解: 神数学模板题-- 数学真奇妙! 前驱

P4725 【模板】多项式对数函数

\(\color{#0066ff}{ 题目描述 }\) 给出 \(n-1\) 次多项式 \(A(x)\),求一个 \(\bmod{\:x^n}\)下的多项式 \(B(x)\),满足 \(B(x) \equiv \ln A(x)\) 在 \(\text{mod } 998244353\)下进行,且 \(a_i \in [0, 998244353] \cap \mathbb{Z}\) \(\color{#0066ff}{输入格式}\) 第一行一个整数 \(n\). 下一行有 \(n\) 个整数,依次

[模板] 多项式全家桶

注意:以下所有说明均以帮助理解模板为目的,不保证正确性. 多项式求逆 已知$A(x)$,求满足$A(x)B(x)=1\ (mod\ x^n)$的B(以下为了方便假设n是2的幂) 考虑倍增,假设已经求出$A(x)B_0(x)=1\ (mod\ x^{n/2})$ $$A(x)(B(x)-B_0(x))=0\ (mod\ x^{n/2})$$ $$(B(x)-B_0(x))=0\ (mod\ x^{n/2})$$ $$(B(x)-B_0(x))^2=0\ (mod\ x^n)$$ $$B^2(x)-

洛谷.3803.[模板]多项式乘法(FFT)

题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. #include <cmath> #include <cctype> #include <cstdio> #include <algorithm> #define gc() getchar() const int N=1e6+5; const double PI=acos(-1); int n,m; struct Complex { double

Luogu【模板】树状数组

https://www.luogu.org/problemnew/show/P3374 单点修改, 区间查询 1 //2018年2月18日17:58:16 2 #include <iostream> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 500001; 7 int n, m; 8 int a[N], c[N]; 9 10 inline int lowbit(int x){ 11 return x &

#50: Luogu 2485 模板

$des$ 1.给定y.z.p,计算y^z mod p 的值: 2.给定y.z.p,计算满足xy ≡z(mod p)的最小非负整数x: 3.给定y.z.p,计算满足y^x ≡z(mod p)的最小非负整数x. $sol$ 模板+模板+模板 #include <bits/stdc++.h> using namespace std; #define LL long long LL n, k; LL Ksm(LL a, LL b, LL p) { LL ret = 1; while(b) { if(