1. 程式人生 > >Luogu 4725 【模板】多項式對數函數

Luogu 4725 【模板】多項式對數函數

但是 += src none 復雜 \n 過程 display rac

繼續補全模板。

要求

$$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; }
View Code

Luogu 4725 【模板】多項式對數函數