多項式 ln

知識前備

首先有複合函數的求導公式:G(x) = F(A(x)) → G'(x) = F'(A(x))A'(x)。

ln 函數的導數:

\[\ln'(x) = \lim_{\delta \to 0} \frac{\ln(x+\delta) - \ln(x)}{\delta} \]

顯然由於 \({\rm e}^{\ln(x+\delta) - \ln(x)} = \dfrac{x + \delta}x\), 那麼, \(\ln(x+\delta) - \ln(x) = \ln(\dfrac{x+\delta}x)\), 於是就有:

\[\ln'(x) = \lim_{\delta \to 0} \frac{\ln(1+\dfrac{\delta}x)}\delta \\ \]

有個通過洛必達法則得出的結論,我沒時間學,只好記了, 那就是 t 趨於 0 的時候, ln(1 + t) 趨近於 t。

那麼上式就是:\(\lim_{\delta \to 0} \dfrac{\dfrac{\delta}x}\delta = \dfrac 1x\)

因此 ln 函數的導函數是 \(\dfrac 1x\)


本題

給定多項式 A(x), 要求求多項式 B(x) 滿足 B(x) ≡ ln(A(x)) mod xn

\[\begin{align} \ln A(x) &\equiv B(x) \mod x^n \\ (\ln A(x))' &\equiv B(x)' \mod x^n \\ \ln'(A(x))A(x)' &\equiv B(x)' \mod x^n \\ \frac {A(x)'}{A(x)} &\equiv B(x)' \mod x^n \end{align} \]

於是求導後積分即可。

多項式求導:axn 的導函數 anxn-1, 常數項滅亡。

void Dervt(int *a, int *b, int n) {
	for(int i = 0; i < n - 1; ++i) b[i] = (LL)a[i + 1] * (i + 1) % mo;
	b[n - 1] = 0;
}

多項式積分,準確的說是不定積分:axn 的反導函數是 axn+1/(n+1)。

void Integ(int *a, int *b, int n) {
	for(int i = 1; i < n; ++i) b[i] = (LL)a[i - 1] * Inv(i) % mo;
	b[0] = 0;
}

容我複習下求逆。

void poly_inv(int deg, int *a, int *b) {
	if(deg == 1) { b[0] = ksm(a[0], mo - 2); return; }
	poly_inv((deg + 1) >> 1, a, b);
	int len = 1; while(len < (deg << 1)) len = len << 1;
	for(int i = 0; i < deg; ++i) c[i] = a[i];
	for(int i = deg; i < len; ++i) c[i] = 0;
	for(int i = 1; i < len; ++i) rv[i] = (rv[i>>1]>>1) | (i&1?len>>1:0);
	NTT(c, len, 1), NTT(b, len, 1);
	for(int i = 0; i < len; ++i) b[i] = (LL)b[i] * (2ll - (LL)c[i] * b[i] % mo) % mo;
	NTT(b, len, -1);
	for(int i = deg; i < len; ++i) b[i] = 0;
}

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;

#define int long long

const int N = 3e5 + 233, mo = 998244353;
int ksm(int a, int b) {
	int res = 1;
	for(; b; b = b>>1, a = ((LL)a * a) % mo)
		if(b & 1) res = ((LL)res * a) % mo;
	return res % mo;
}
const int g = 3, ig = ksm(g, mo - 2);

void Dervt(int n, int *a, int *b) {
	for(int i = 0; i < n - 1; ++i) b[i] = (LL)a[i + 1] * (i + 1ll) % mo;
	b[n - 1] = 0;
}

void Integ(int n, int *a, int *b) {
	for(int i = 1; i < n; ++i) b[i] = (LL)a[i - 1] * ksm(i, mo - 2) % mo;
	b[0] = 0;
}

int rv[N], t[N], n;
void NTT(int *a, int n, int type) {
	for(int i = 0; i < n; ++i) if(i < rv[i]) swap(a[i], a[rv[i]]);
	for(int m = 2; m <= n; m = m << 1) {
		int w = ksm(type == 1 ? g : ig, (mo - 1) / m);
		for(int i = 0; i < n; i += m) {
			int tmp = 1;
			for(int j = 0; j < (m >> 1); ++j) {
				int p = a[i + j] % mo, q = (LL)tmp * a[i + j + (m >> 1)] % mo;
				a[i + j] = (p + q) % mo, a[i + j + (m >> 1)] = (p - q + mo) % mo;
				tmp = (LL)tmp * w % mo;
			}
		}
	}
	if(type == -1) {
		int Inv = ksm(n, mo - 2);
		for(int i = 0; i < n; ++i) a[i] = (LL)a[i] * Inv % mo;
	}
}

void poly_inv(int deg, int *a, int *b) {
	if(deg == 1) { b[0] = ksm(a[0], mo - 2); return; }
	poly_inv((deg + 1) >> 1, a, b);
	int len = 1; while(len < (deg << 1)) len = len << 1;
	for(int i = 0; i < deg; ++i) t[i] = a[i];
	for(int i = deg; i < len; ++i) t[i] = 0;
	for(int i = 1; i < len; ++i) rv[i] = (rv[i>>1]>>1) | (i&1 ? len>>1 : 0);
	NTT(b, len, 1), NTT(t, len, 1);
	for(int i = 0; i < len; ++i) b[i] = (LL)b[i] * (2ll - (LL)t[i] * b[i] % mo) % mo;
	NTT(b, len, -1);
	for(int i = deg; i < len; ++i) b[i] = 0;
}

int b[N], c[N];
void poly_ln(int *a, int n) {
	poly_inv(n, a, b), Dervt(n, a, c);
	int len = 1; while(len < (n << 1)) len = len << 1;
	for(int i = n; i < len; ++i) b[i] = c[i] = 0;
	for(int i = 1; i < len; ++i) rv[i] = (rv[i >> 1] >> 1) | (i & 1 ? len >> 1 : 0);
	NTT(b, len, 1), NTT(c, len, 1);
	for(int i = 0; i < len; ++i) b[i] = (LL)b[i] * c[i] % mo;
	NTT(b, len, -1);
	Integ(n, b, a);
}

int a[N]; 

signed main() {
	scanf("%d", &n);
	for(int i = 0; i < n; ++i) scanf("%lld", &a[i]), a[i] %= mo;
	poly_ln(a, n);
	for(int i = 0; i < n; ++i) cout << (a[i] + mo) % mo << ' ';
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章