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...