補補補……
這個題的解法讓我認識到了泰勒展開的美妙之處。
泰勒展開就是用乙個多項式型的函式去逼近乙個難以準確描述的函式。
有公式在這裡$g^$表示$g$的$n$階導。
在$0$這個點的泰勒展開$(x_0 = 0)$叫做麥克勞林級數,利用這個東西可以很精確地去逼近原來的函式。
比如,有了泰勒展開之後我們可以定義一些看上去很難定義的東西,比如這個多項式取$ln$:
$$ln(1 - a(x)) = -\sum_^\frac$$
這也解釋了為什麼給出的多項式常數項一定是$1$。
同理,多項式$exp$的定義是這樣子的:
$$exp(a(x)) = \sum_^\frac$$
可以發現這樣子定義之後就好理解很多了。
牛頓迭代是解決多項式問題的利器,可以一口氣解決好多推式子問題。
牛頓法求解方程的近似解在高中課本裡面有提到過,它也可以用來解決多項式的問題。
現在我們嘗試用另一種手段得到它。
要求$g(f(x)) \equiv 0 (\mod x^n)$,通過題目給出的特定的$g(x)$,我們可以算出$f(x)$。
首先我們嘗試解決常數項的問題,一般來說,這個問題都非常簡單,比如本題中可以直接求出常數項為$1$。
現在假設已經求出了$f_0(x)$滿足$g(f_0(x)) \equiv 0(\mod x^ \right \rceil})$,我們嘗試求$f(x)$滿足$g(f(x)) \equiv 0 (\mod x^n)$。
可以對$g(x)$在$f_0(x)$處進行泰勒展開,得到
$$g(f(x)) = g(f_0(x)) + g'(f_0(x))(f(x) - f_0(x)) + g''(f_0(x))(f(x) - f_0(x))^2 + \cdots$$
這是在$(\mod x^n)$次意義下進行的,在多項式求逆的時候已經證明過了$(f(x) - f_0(x))^n$在$n \geq 2$的時候模$x^n$為$0$,後面就可以不用寫下去了。
注意到$g(f(x)) \equiv 0 (\mod x^n)$,有
$$f(x) \equiv f_0(x) - \frac(\mod x^n)$$
這個式子就是牛頓迭代的式子了。
鼓掌~~~
考慮一下在這個題中怎麼取這個$g(x)$。
題目要求
$$b(x) \equiv e^ (\mod x^n)$$
發現這個$e^x$並不是很方便,所以兩邊取一下$ln$,移項,
$$ln(b(x)) - a(x) \equiv 0 (\mod x^n)$$
那就記$g(f(x)) = lnf(x) - a(x)$。
因為$a(x)$和$f(x)$在這裡等價於兩個數,$f(x)$是自變數,所以$a(x)$就看成常數,在求導的時候可以直接消掉。
整理一下就得到了多項式$exp$的式子:
$$f(x) = f_0(x)(1 - lnf_0(x) + a(x))$$
左轉去複製各種模板過來,於是就可以愉快地遞迴求解了!
時間複雜度仍然是$o(nlogn)$。
在吉老師部落格裡看到了關於這堆東西常數的吐槽,感覺妙不可言。
code:
#include #includeview code#include
using
namespace
std;
typedef
long
long
ll;const
int n = 1
<< 18
;int
n;ll f[n], g[n];
namespace
poly
return
res;
}inline
void prework(int
len)
inline
void ntt(ll *c, int
opt) }}
if (opt == -1
) }
void inv(ll *a, ll *b, int
len)
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)
inline
void integ(ll *c, int
len)
inline
void ln(ll *a, ll *b, int
len)
ll f[l], g[l];
void exp(ll *a, ll *b, int
len)
exp(a, b, (len + 1) >> 1
);
ln(b, f, len);
f[0] = (a[0] % p + 1 - f[0] + p) %p;
for (int i = 1; i< len; i++) f[i] = (a[i] - f[i] + p) %p;
prework(len
<< 1
);
for (int i = len; i < lim; i++) f[i] = 0
;
for (int i = 0; i < lim; i++) g[i] = 0
;
for (int i = 0; i < len; i++) g[i] =b[i];
ntt(f,
1), ntt(g, 1
);
for (int i = 0; i < lim; i++) f[i] = f[i] * g[i] %p;
ntt(f, -1
);
for (int i = 0; i < lim; i++) b[i] =f[i];
}};template
inline
void read(t &x)
intmain()
取不同的$g(x)$可以得到不同的結果,簡單推導出答案的式子。
比如:多項式求逆,
$$g(f(x)) = f(x)a(x) - 1$$
多項式開方,
$$g(f(x)) = f(x)^2 - a(x)$$
還有一些應該會在做題的時候補全。
多項式模板
檢查資料 input 61 2 3 4 5 6 1.ntt多項式求逆 include define maxn 2100005 define ll long long define mod 998244353 using namespace std int lg maxn r maxn w maxn ...
Luogu 4238 模板 多項式求逆
瘋狂補板中。考慮倍增實現。假設多項式只有乙個常數項,直接對它逆元就可以了。現在假如要求 g x f x g x equiv 1 mod x n 而我們已經求出了 h x f x h x equiv 1 mod x right rceil 兩式相減,f x g x h x equiv 0 mod x ...
洛谷P4726 模板 多項式指數函式
多項式牛頓迭代 公式 f z equiv f 0 z frac pmod 以下截圖自金策2015 研究了很久都沒有明白那個泰勒展開的求導為什麼是對的.好像是把a x 當成了 常數項 把f看成 變數 但是g這個函式應該是輸入乙個函式輸出乙個函式吧,根本就不是一般的函式,真的能求導嗎?但是這種做法的確具...