很早就想學fft那套理論,但抱著能咕一天是一天的態度咕到了今天
fft是幹什麼的?
求兩個多項式卷積的,比如$g=a*b$($g_x=\sum}$)
顯然暴力乘是$o(n^2)$的,然而我們可以把他優化到$o(n\;log\;n)$
一般來將,多項式是用每一項的係數表示的,而還可以用點值來表示,比如乙個多項式$a$有n項,我們可以讓變數x取n個不同的值,然後用n個得出來的值表示這個多項式
由於是點值,兩個多項式相乘時只要把對應的點值相乘即可,這是$o(n)$的
顯然我們容易可以把兩個表示法互相轉換,比如$n^2$暴力和$n^3$高斯消元
這似乎比暴力還要不優越,所以我們要優化轉化表示法的複雜度
我們發現我們可以隨便選數x,只要x各不相同就行,然而當x在大部分取值時,都要暴力算$x^i$的值,這很不優越
所以我們的數學知識告訴我們數不只有實數,還有虛數啊懶得介紹虛數,我去拖一點東西過來
虛數大概就是可以表示在乙個復平面上的東西,k次單位根$w_k$就是其k次方是1的東西$w_k$的i次方都在乙個以原點為圓心,1為半徑的圓上
由於複數運算的種種性質(幅角相加,長度相乘),這些東西是繞原點順時針的,然後我們把i次單位根代入多項式來求值,這就是可以優化的了
然後我們就可以用分治來優化啦
把多項式分成奇數項和偶數項兩部分然後分治,就像這樣
愉快地盜了張圖來 原文
由於要按照奇偶性分治,分治後的順序會和原來不同,為了讓實現更方便,可以把原下標的二進位制翻轉後當新下標(不會證)
那麼我們就可以把係數表示變成點值表示了,這就是dft
然後怎麼把點值還原成係數呢,據說只要把點值除第一項的、部分翻轉,然後跑dft,再把結果除以n就好了(還是不會證)
大概就這樣吧我感覺講的海星
例題有這個(
模板)多項式乘法(fft)
ac**
#includeusingview codenamespace
std;
#define int long long
intn,m,i,j,len;
int w[5000000],f[5000000],g[5000000
];int rev[5000000],bit,ha=998244353
;inline
void getrev(int n)
int add(int x)
int jian(int x)
inline
int qpow(int a,intb);
return
ans;
}void fft(int *a,int n,int
x) }
int ni=qpow(n,ha-2
);
if(x)for(int i=0;iha;
}signed main()
fft還有模意義下的版本ntt
只要把單位根變成模數的原根就行了,一般都是3,如998244353(1e9+7不是ntt模數)
如果要求沒有原根的多項式乘法,可以用crt把有原根的答案結合起來
再來道例題
ac**
#includeusingview codenamespace
std;
#define int long long
intn,m,i,j,len;
int w[2100000],f[2100000],g[2100000
];int rev[2100000],bit,ha=998244353
;inline
void getrev(int n)
int add(int x)
int jian(int x)
inline
int qpow(int a,intb);
return
ans;
}void fft(int *a,int n,int
x) }
int ni=qpow(n,ha-2
);
if(x)for(int i=0;iha;
}signed main()
FFT學習筆記
fft可用於解決一些卷積問題。一般問題形式如下 c a b c i ij 0a i b i j 若把a,b看成兩個次數為n多項式 a x ni 0 a i xi,b x ni 0b i x i 原問題等於兩個多項式相乘,c的次數等於2n 1 乙個次數界為n的多項式a的點值表達為n個點值對所組成的集合...
FFT學習筆記
今天doggu講了,開始覺得這玩意好強啊 後來自己看的時候發現蠻zz wys表示 贊同 所以很多自己覺得遙不可及,一輩子都不可能學會的東西只要慢慢理解,理解好了再把他化為自己的語言,歸到自己的世界裡 就覺得不是很難了,甚至很簡單.當然開始並不是,從 好難啊 到 這麼簡單困大爺我這麼久,之前腦子抽了z...
FFT 學習筆記
f x sum limits a i x i x 0,f x 0 x 1,f x 1 x f x 首先我們要了解複數 即 i sqrt 乙個數有實部和虛部 即 a x y i x,y 原來的實數運算相當於在乙個一維數軸上進行移動,複數則是在二維平面上運動 一句話來說就是摸長相乘,幅角相加 c 中提供...