跳到主要内容

快速傅立叶变换(FFT)

复数

struct Comp
{
double real,imag;
Comp(double real=0.0,double imag=0.0):real(real),imag(imag){}
Comp operator+(const Comp &rhs) const{return Comp(real+rhs.real,imag+rhs.imag);}
Comp operator-(const Comp &rhs) const{return Comp(real-rhs.real,imag-rhs.imag);}
Comp operator*(const Comp &rhs) const{return Comp(real*rhs.real-imag*rhs.imag,real*rhs.imag+rhs.real*imag);}
Comp operator/(const Comp &rhs) const{return Comp((real*rhs.real+imag*rhs.imag)/(rhs.real*rhs.real+rhs.imag*rhs.imag),(imag*rhs.real-real*rhs.imag)/(rhs.real*rhs.real+rhs.imag*rhs.imag));}
};

实现

using Comp=complex<double>;
const double pi=acos(-1.0);
const int N=1<<20;
Comp tmp[N<<1];
void fft(Comp *f,int lim,int type)
{
if(lim==1)return;
for(int i=0;i<lim;i++)tmp[i]=f[i];
for(int i=0;i<(lim>>1);i++)
{
f[i]=tmp[i<<1];
f[i+(lim>>1)]=tmp[(i<<1)+1];
}
Comp *g=f,*h=f+(lim>>1);
fft(g,lim>>1,type);
fft(h,lim>>1,type);
Comp cur(1,0),step(cos(2*pi/lim),sin(2*pi/lim)*type);
for(int i=0;i<(lim>>1);i++)
{
tmp[i]=g[i]+cur*h[i];
tmp[i+(lim>>1)]=g[i]-cur*h[i];
cur*=step;
}
for(int i=0;i<lim;i++)f[i]=tmp[i];
}

例题

洛谷 P3803 【模板】多项式乘法(FFT)

给定一个 nn 次多项式 F(x)F(x),和一个 mm 次多项式 G(x)G(x)

请求出 F(x)F(x)G(x)G(x) 的乘积。

参考代码
#include <bits/stdc++.h>
using namespace std;

using Comp=complex<double>;
const double pi=acos(-1.0);
const int N=1<<20;
Comp a[N<<1],b[N<<1],tmp[N<<1];
int c[N<<1];
void fft(Comp *f,int lim,int type)
{
if(lim==1)return;
for(int i=0;i<lim;i++)tmp[i]=f[i];
for(int i=0;i<(lim>>1);i++)
{
f[i]=tmp[i<<1];
f[i+(lim>>1)]=tmp[(i<<1)+1];
}
Comp *g=f,*h=f+(lim>>1);
fft(g,lim>>1,type);
fft(h,lim>>1,type);
Comp cur(1,0),step(cos(2*pi/lim),sin(2*pi/lim)*type);
for(int i=0;i<(lim>>1);i++)
{
tmp[i]=g[i]+cur*h[i];
tmp[i+(lim>>1)]=g[i]-cur*h[i];
cur*=step;
}
for(int i=0;i<lim;i++)f[i]=tmp[i];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i=0;i<=n;i++)
{
double x;
cin>>x;
a[i]=Comp(x,0);
}
for(int i=0;i<=m;i++)
{
double x;
cin>>x;
b[i]=Comp(x,0);
}
int lim=1;
while(lim<=n+m)lim<<=1;
fft(a,lim,1);
fft(b,lim,1);
for(int i=0;i<lim;i++)a[i]*=b[i];
fft(a,lim,-1);
for(int i=0;i<=n+m;i++)c[i]=a[i].real()/lim+0.5;
for(int i=0;i<=n+m;i++)cout<<c[i]<<' ';
return 0;
}

洛谷 P1919 【模板】高精度乘法 | A*B Problem 升级版

给你两个正整数 a,ba,b,求 a×ba \times b。(1a,b1010000001\le a,b \le 10^{1000000}

参考代码
#include <bits/stdc++.h>
using namespace std;

using Comp=complex<double>;
const double pi=acos(-1.0);
const int N=1<<20;
Comp a[N<<1],b[N<<1],tmp[N<<1];
int c[N<<1];
void fft(Comp *f,int lim,int type)
{
if(lim==1)return;
for(int i=0;i<lim;i++)tmp[i]=f[i];
for(int i=0;i<(lim>>1);i++)
{
f[i]=tmp[i<<1];
f[i+(lim>>1)]=tmp[(i<<1)+1];
}
Comp *g=f,*h=f+(lim>>1);
fft(g,lim>>1,type);
fft(h,lim>>1,type);
Comp cur(1,0),step(cos(2*pi/lim),sin(2*pi/lim)*type);
for(int i=0;i<(lim>>1);i++)
{
tmp[i]=g[i]+cur*h[i];
tmp[i+(lim>>1)]=g[i]-cur*h[i];
cur=cur*step;
}
for(int i=0;i<lim;i++)f[i]=tmp[i];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s1,s2;
cin>>s1>>s2;
int n=s1.length()-1,m=s2.length()-1;
for(int i=0;i<=n;i++)a[i]=Comp(s1[n-i]-'0',0);
for(int i=0;i<=m;i++)b[i]=Comp(s2[m-i]-'0',0);
int lim=1;
while(lim<=n+m)lim<<=1;
fft(a,lim,1);
fft(b,lim,1);
for(int i=0;i<lim;i++)a[i]=a[i]*b[i];
fft(a,lim,-1);
for(int i=0;i<=n+m;i++)c[i]=a[i].real()/lim+0.5;
int t=0;
while(t<=n+m||c[t])
{
c[t+1]+=c[t]/10;
c[t++]%=10;
}
for(int i=t-1;i>=0;i--)cout<<c[i];
return 0;
}