對數和指數是很重要的東西了,複雜的多項式都和他們有關係,所以說掌握很重要,這裏不建議光背板子,因爲這兩個板子都有致命的限制,而在實際操作的時候,可以通過一些方法繞過這個限制直接求解,這個就很重要了。
1. 多項式的
公式先走起咯:
觀察公式,一句話解決:
導卷逆的積:
看上去很模板,當然模板也是很短的:
inline Polynomial Logarithmic(const Polynomial &a){
Polynomial ln_a=Derivation(a)*Inverse(a);
ln_a.resize(a.size());
//這裏resize一下,因爲卷積後會倍增,防止變長爆掉
return Integral(ln_a);
}
還有一個值得注意的問題,一般求對數的多項式,是需要要求常數項爲 的,因爲我們知道:
也就是:
這樣算出來的 常數項是 ,而我們追後一步在算積的時候,是默認把常數項補上 的,這樣就沒有問題。可要是原多項式常數項不爲 呢?
顯然應該算積的時候在常數項補上 (C爲常數項),不過這個數在模的意義下應該是多少呢?這個問題周道確實不能解決了,所以說,模板題的話,會給出這個常數項爲 的條件的。
否認常數項不等於,完全不能求 的說法。
2. 多項式的
這玩意說簡單也簡單,說複雜也挺複雜的,我們得引入一個新玩意,【牛頓迭代】,是求函數零點的玩意,收斂速度非常理想,我在這裏有簡略的講過:【導數和牛頓迭代】,我也在洛谷出過一個牛頓迭代的裸題,感興趣可以去體驗一下牛頓迭代的神奇:【P4986 逃離】。
說遠了,現在我們來康康怎麼求指數函數。
令我們要求的是 的指數函數 ,既是:
變形得:
咦? ?,我們把多項式當做函數值看看?
哇,函數零點!馬上牛頓迭代呀!
設,我們要求 的零點,根據牛頓迭代的公式可得(注意這裏B後面的括號的迭代版本的意思,不是多項式的項):
而根據導數的定義,,(【導數和牛頓迭代】裏面有提到過一點,這裏是把當做常數捨去了)
那我們現在把牛頓迭代的公式化簡:
再次強調B後面的括號的迭代版本的意思,不是多項式的項。
現在看似分治可做,我們用兩個容器相互裝版本。每次老版本一卷,新版本長度就會倍增,所以說我們做 次迭代就好。我們的操作相當於把式子拆了求收斂值,所以不會有精度的問題,求出來就好了。
那麼現在的問題是,第一個版本是怎麼樣,洛咕模板給的是保證 ,因爲,也就是,所以說 ,也就是常數項爲 。
當然了,同理,他一般會保證,我們不方便找到其他模的意義下的值。如果可以算的話,可以在模板裏面傳入 也就是 的值。
否認不等於,完全不能求 的說法。
inline Polynomial Exponential(const Polynomial &a,int Constant=1){
Polynomial ret,D;int ed=a.size();
ret.resize(1);ret[0]=Constant;
for(int len=2;len<=ed;len<<=1){
D=Logarithmic(ret);D.resize(len);
D[0]=(1ll*a[0]+1ll-D[0]+mod)%mod;
for(int i=1;i<len;++i) D[i]=(1ll*a[i]-D[i]+mod)%mod;
int n=Prepare_Transformation(len<<1);
ret.resize(n);D.resize(n);
NTT(ret,1);NTT(D,1);
for(int i=0;i<n;i++)ret[i]=1ll*ret[i]*D[i]%mod;
NTT(ret,-1);
for(int i=len;i<(len<<1);++i)ret[i]=D[i]=0;
}
ret.resize(ed);
return ret;
}