FFT學習小記

2021-07-15 12:38:08 字數 2932 閱讀 3426

oi中會遇到計算卷積形式的式子的問題,要用到fft

例題:【zjoi2014】力 【tjoi&heoi2016】求和

fft分為兩部分:點值和插值運算

c=a*b,次數界為n

首先是點值:對a和b求在n次單位複數根下的點值點值對((w0

n,y0

),(w1

n,y1

)…(wn

−1n,

yn−1

))然後兩個相乘得出c的點值對,再運用插值運算得出c

插值:點值的逆運算

令n為二的冪,x為乙個根,然後要對a進行點值運算

分解成兩個式子a0,a1,其中

那麼a(x)=a[0] (x2

)+xa[1] (x2

) 但是這樣做陣列空間會炸,所以需要優化

首先考慮分解。對a不停分解可以分成乙個滿二叉樹,如圖:

觀察每一層。其實每一層乘出來都只有8個值

假設深度從上至下為1——n。合併的時候,對於第i層的元素,它們二進位制最低i位都是相同的。

那麼求出a在最底層的順序(可以發現是i在二進位制下的反序),即可充分利用陣列空間。

對於插值運算,相當於點值運算的結果乘上點值運算矩陣的逆矩陣。

令點值運算矩陣為v1

n ,那麼它的位置(i,j)元素為wi

jn令逆矩陣為v−

1n,那麼v−

1n的位置(i,j)的元素為w−

kjn/

n 可以根據n次單位複數根求和定理證明。

那麼把y和a交換(y是點值運算結果),用w−

1n替掉w1

n ,然後做dft,最後結果除以n即可。

有時為了避免誤差,題目會出成取模的。

但是這樣一般對模數有要求,一般為2a

∗b+1

形式出現(如998244353等)

x也不能取n次單位複數根了,需要取合適的一些數,使得它們有n次單位複數根的性質。 令m

o=kn

+1(n為次數界),那麼wn

=gkm

odp

g是模數的原根,大多數題目的g取3

剩下的和dft一樣了。逆dft預處理逆元。

**1(實數運算)(題目是【zjoi2014】力)

#include 

#include

#include

#include

using namespace std;

const int maxn=262205;

typedef double db;

const db pi=acos(-1);

int n,m;

struct z

};z operator + (z a,z b)

z operator - (z a,z b)

z operator * (z a,z b)

//定義運算

z q[maxn],q[maxn],t[maxn],r[maxn],a[maxn],b[maxn];

db time,a[maxn],b[maxn];

void dft(z *a,int sig)

for (int l=2;l<=m;l*=

2)//自下而上求解}}

for (int i=0;i

}void fft(z *a,z *b,db *c)

int main()

time=log(m)/log(2);

fft(q,r,a); fft(q,r,b);

for (int i=0;iprintf("%.4lf\n",a[i]-b[n-i-1]);

return

0;}

**2(取模的)(題目【tjoi&heoi2016】求和)

#include 

#include

#include

#include

using

namespace

std;

const

int maxn=262205,mo=998244353;

typedef

long

long ll;

int n,m,fact[maxn],inv[maxn],w[maxn],a[maxn],b[maxn],c[maxn],t[maxn],ans;

double time;

int quick(int x,int t)

void dft(int *a,int sig)

for (int l=2;l<=m;l*=2)}}

for (int i=0;ivoid ntt(int *a,int *b,int *c)

w[0]=1; w[1]=quick(3,(mo-1)/m);

for (int i=2;i<=m;i++) w[i]=(ll)w[i-1]*w[1]%mo;//預處理逆元

b[0]=1; b[1]=n+1;

for (int i=0;i<=n;i++) a[i]=(i&1)?-inv[i]:inv[i];

for (int i=2;i<=n;i++) b[i]=(ll)(quick(i,n+1)-1)*quick(i-1,mo-2)%mo*inv[i]%mo;

time=log(m)/log(2);

ntt(a,b,c);

int tmp=1;

for (int i=0;i<=n;i++)

ans=(ans+mo)%mo;

printf("%d\n",ans);

return

0;}

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學習

define fon i,s for int i 0 it i define doxe i,f,t for int i f i t i define ifm a,b if a b define swp a,b std swap a,b define lp while 1 define qlp bre...