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:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }