最近閒著無聊研究了下\(fft\)的常數優化,大概就是各種\(3\)次變\(2or1.5\)次之類的,不過沒見過啥題卡這個的吧。
關於\(fft\)可以看這裡:**fft&ntt。
設\(x=a+bi\),其中\(i\)是虛數單位,那麼我們用\(\bar x\)表示\(x\)的共軛複數,即\(\bar x=a-bi\)。
共軛複數有乙個這樣的性質:
\[\overline=\bar a \cdot \bar b
\]證明展開就好了,這個是下面優化的關鍵。
設\(\omega_n\)為\(n\)階單位根,則\(\overline}=\omega_^\)。
設\(f(x)=\sum_^a_ix^i\),注意到:
\[n\cdot[j](f)=\sum_^\omega_^a_i=a_0+\sum_^\omega_^a_
\]也就是說我們如果進行一次std::reverse(a+1,a+n)
,然後dft(a)
,在除以\(n\),我們就完成了一次\(idft\)。
給出多項式\(f(x)=\sum_^a_ix^i,g(x)=\sum_^b_ix^i\),求其卷積。
這裡最開始介紹一種非常簡潔的優化方法,構造多項式\(h(x)\):
\[h(x)=f(x)+ig(x)
\]\[h^2(x)=f^2(x)-g^2(x)+2if(x)g(x)
\]那麼我們只需要取\(h^2(x)\)的虛部除以\(2\)就是答案,這只需要做兩次\(fft\)。
這個和上面的關聯不大,設\(x_i\)表示多項式\(f(x)\)
\(dft\)之後的係數,\(a_i\)表示\(dft\)之前的係數,設\(f(x)\)為\(n\)項的多項式,且\(n=2^k\),注意到:
\[x_i=\sum_^a_j\omega_^,x_=\sum_^a_j\omega_^
\]即:\(x_i=\overline}\)。
這實質上是因為\(f\)沒有虛部的原因,我們換乙個有虛部的多項式試試:
\[x_i=\sum_^(a_j+ib_j)\omega_^\\
x_=\sum_^(a_j+ib_j)\omega_^\\
\overline}=\sum_^(a_j-ib_j)\omega_^\\
\]等等,我們發現第乙個式子和第三個式子很像,兩式相加減可以得到:
\[x_i+\overline}=2\sum_^a_j\omega_^\\
x_i-\overline}=2i\sum_^b_j\omega_^
\]注意到等式右邊就是\(a\)
\(dft\)完之後的結果,那麼對於多項式\(f(x),g(x)\),我們可以構造乙個函式然後\(dft\)一次,然後\(o(n)\)得到兩個多項式\(dft\)之後的結果,總共只用了一次\(fft\)。
當然這個玩意也可以這樣用:假設我們現在想求\(dft(f(x))\),我們把\(f(x)\)奇偶分類,構造多項式:
\[g(x)=\sum_^(a_+ia_)x^i
\]然後相當於是\(0.5\)次\(fft\)來完成這個事,設\(dft(g(x))\)每一項為\(x_i\),\(dft(f(x))\)每一項為\(y_i\),那麼推一下可以得到:
\[y_i=\frac}}-2\omega_^i(x_i-\overline})
\]注意這裡只有\(i\in [0,n/2)\)的值,\(y_\)特殊處理一下,後面的可以通過前面得到。
\(\rm mtt\)就是拆係數\(\rm fft\),設多項式\(s(x),t(x)\),我們要算\(s(x)t(x)\),模數任意。
我們拆係數,設拆完了之後是\(s(x)=a(x)+b(x)\cdot p,t(x)=c(x)+d(x)\cdot p\)。
構造\(f(x)=a(x)+i\cdot b(x)\),\(g(x)=c(x)+i\cdot d(x)\)。
那麼有:
\[\begin
&f(\omega_n^j)=\sum_^(a_i+ib_i)\omega_n^\\
&f(\omega_n^)=\sum_^(a_i+ib_i)\omega_n^\\
&\overline)}=\sum_^(a_i-ib_i)\omega_n^\\
\end
\]那麼相加減可得\(a(x),b(x)\)的\(dft\)。
令\(h(x)=(a(x))\cdot (g(x))=(a(x)\cdot g(x))=(a(x)c(x)+i\cdot a(x)d(x))\)。
那麼我們\(idft\)一次\(h(x)\)就可以得到\(a(x)c(x),a(x)d(x)\)。
同理可以得到\(b(x)c(x),b(x)d(x)\),一共\(4\)次\(dft\)。
**長這樣:
void mul(int *r,int *s,int *t,int len) fft(g[2]),fft(g[3]);
for(int i=0;ifor(int i=0;i}
神奇的常數優化
話說noip不開優化,那我們來看看開優化後會發生什麼 乙個簡單的累加 include include 計時看看差別 includeusing namespace std int main 按理來說,上面的兩種方法差不多 在devc 5.7.1中,xp系統 學校機房的那種 不開任何優化 大約前一種是8...
神奇的常數優化
話說noip不開優化,那我們來看看開優化後會發生什麼 乙個簡單的累加 include include 計時看看差別 includeusing namespace std intmain 按理來說,上面的兩種方法差不多 在devc 5.7.1中,xp系統 學校機房的那種 不開任何優化 大約前一種是85...
矩陣乘法的常數優化
矩陣乘法的常數優化 philipsweng 雖然說作為鍵盤科學家,我們更應該關心程式的時間複雜度。但是乙個寫的不好的程式可能在實際執行會跟時間複雜度更差的程式差不了多少。我們我們也應該注意程式的常數優化。對於矩陣乘法來講。我們實際上可以比較這兩種打法。實際上第二種打法在絕大多數情況下效率約為第一種的...