Kyopro Library
 
読み取り中…
検索中…
一致する文字列を見つけられません
convolution.hpp
[詳解]
1#include"../../kyopro_library/template.hpp"
2
3/// @brief 高速フーリエ変換
4/// @note O(N log(N))
5/// @details f(x) = Σ a[i]x^i, w^N = 1 とすると、F(t) = Σ f(w^i)t^i の各係数を返す。
6/// @details a = (a[0], a[1], ..., a[n-1]) -> fa = (f(w^0), f(w^1), ..., f(w^(n-1)))
7void FFT(vector<complex<double>>& a, bool inv=false) {
8 int n=a.size(),h=0;
9 while((1<<h)<n) h++;
10 for(int i=0; i<n; i++) {
11 int j=0;
12 //ビットを逆に
13 for(int k=0; k<h; k++) j|=(i>>k&1)<<(h-1-k);
14 if(i<j) swap(a[i],a[j]);
15 }
16
17 for(int b=1; b<n; b<<=1) {
18 for(int j=0; j<b; j++) {
19 //b = ブロックサイズの半分
20 //j, j+b を計算
21 //w = exp(-2πj / 2b) = 1 の b 乗根の j 乗
22 complex<double> w=polar(1.0,(2.0*M_PI)/(2.0*b)*j*(inv?1:-1));
23 //ブロックサイズ 2b だけずらしながら計算
24 for(int k=0; k<n; k+=b*2) {
25 complex<double> s=a[j+k],t=a[j+k+b]*w;
26 a[j+k]=s+t,a[j+k+b]=s-t;
27 }
28 }
29 }
30
31 if(inv)for(int i=0; i<n; i++) a[i]/=n;
32}
33
34/// @brief 畳み込み
35/// @note O(N log(N))
36vector<double> Convolve(const vector<double>& a, const vector<double>& b) {
37 int n=1;
38 while(n+1<a.size()+b.size()) n*=2;
39 vector<complex<double>> fa(n),fb(n);
40 for(int i=0; i<a.size(); i++) fa[i]=a[i];
41 for(int i=0; i<b.size(); i++) fb[i]=b[i];
42
43 // fa, fb を高速フーリエ変換
44 FFT(fa); FFT(fb);
45 // fa' * fb' を計算
46 for(int i=0; i<n; i++) fa[i]*=fb[i];
47 // fa' * fb' を逆高速フーリエ変換し、fa * fb の係数を得る
48 FFT(fa,true);
49
50 vector<double> ret(n); for(int i=0; i<n; i++) ret[i]=fa[i].real();
51 return ret;
52}
vector< double > Convolve(const vector< double > &a, const vector< double > &b)
畳み込み
void FFT(vector< complex< double > > &a, bool inv=false)
高速フーリエ変換