个人理解:该算法用来加速多项式乘法,卷积操作,生成函数的乘积,时间复杂度o(nlogn),关键在于系数表达式到点值表达式的转换(DFT),以及IDFT的优化,
同时应用了n次单位根的优越性,FFT(a,n,1),FFT(a,n,-1)即可在点值与系数之间进行转换。
注意细节:1.FFT因应用了复数,存在着误差,不适用取模操作
2.多项式相乘的时候,注意n的取值,一定为2的幂指数倍
欠缺:应用不够熟练,对什么时候该建模,什么时候对算式进行化简尚未很清晰,需要多做题目
入门题目:
题解:FFT入门模板题
#include <bits/stdc++.h> using namespace std; const int maxn = 4e6+10; const double pi = acos(-1); struct CP { double x, y; CP(){} inline CP(double a, double b):x(a),y(b){} inline CP operator + (const CP&r) const { return CP(x + r.x, y + r.y); } inline CP operator - (const CP&r) const { return CP(x - r.x, y - r.y); } inline CP operator * (const CP&r) const { return CP(x*r.x-y*r.y, x*r.y+y*r.x); } inline CP conj() { return CP(x, -y); } } a[maxn], b[maxn], t; int n, m; inline void Swap(CP&a, CP&b) { t = a; a = b; b = t; } inline void FFT(CP*a, int n, int f) { if(n==1) return;int i, j, k; for(i = j = 0; i < n; ++ i) { if(i > j) Swap(a[i], a[j]); for(k = n>>1; (j ^= k) < k; k >>= 1); } for(i = 1; i < n; i <<= 1) { CP wn(cos(pi/i), f*sin(pi/i)); for(j = 0; j < n; j += i<<1) { CP w(1, 0); for(k = 0; k < i; ++ k, w=w*wn) { CP x = a[j+k], y = w*a[i+j+k]; a[j+k] = x+y; a[i+j+k] = x-y; } } } } int main() { scanf("%d%d",&n,&m);int len=n+m; for(int i = 0; i <= n; ++ i) scanf("%lf",&a[i].x); for(int i = 0; i <= m; ++ i) scanf("%lf",&b[i].x); for(m += n, n = 1; n <= m; n <<= 1); FFT(a, n, 1);FFT(b,n,1); for(int i=0;i<=n;i++) a[i]=a[i]*b[i]; FFT(a, n,-1); for(int i=0;i<=len;i++) if(i==0) printf("%d",(int)(a[i].x/n+0.5));else printf(" %d",(int)(a[i].x/n+0.5)); printf("\n"); return 0; }
2.P1919 【模板】A*B Problem升级版(FFT快速傅里叶)
题解:FFT入门模板题
#include <bits/stdc++.h> using namespace std; const int maxn = 4e6+10; const double pi = acos(-1); struct CP { double x, y; CP(){} inline CP(double a, double b):x(a),y(b){} inline CP operator + (const CP&r) const { return CP(x + r.x, y + r.y); } inline CP operator - (const CP&r) const { return CP(x - r.x, y - r.y); } inline CP operator * (const CP&r) const { return CP(x*r.x-y*r.y, x*r.y+y*r.x); } inline CP conj() { return CP(x, -y); } } a[maxn], b[maxn], t; int n, m;int res[maxn]; inline void Swap(CP&a, CP&b) { t = a; a = b; b = t; } inline void FFT(CP*a, int n, int f) { if(n==1) return;int i, j, k; for(i = j = 0; i < n; ++ i) { if(i > j) Swap(a[i], a[j]); for(k = n>>1; (j ^= k) < k; k >>= 1); } for(i = 1; i < n; i <<= 1) { CP wn(cos(pi/i), f*sin(pi/i)); for(j = 0; j < n; j += i<<1) { CP w(1, 0); for(k = 0; k < i; ++ k, w=w*wn) { CP x = a[j+k], y = w*a[i+j+k]; a[j+k] = x+y; a[i+j+k] = x-y; } } } } char s[61000]; int main() { scanf("%d",&n); scanf("%s",&s);for(int i = 0; i < n; ++ i) a[i].x=1.0*(s[n-i-1]-'0'); scanf("%s",&s);for(int i = 0; i < n; ++ i) b[i].x=1.0*(s[n-i-1]-'0'); for(m = 2*n, n = 1; n <= m; n <<= 1); FFT(a,n,1);FFT(b,n,1); for(int i=0;i<=n;i++) a[i]=a[i]*b[i]; FFT(a,n,-1); for(int i=0;i<=n;i++) res[i]=(int)(a[i].x/n+0.5); for(int i=0;i<=n;i++) res[i+1]+=res[i]/10,res[i]%=10; int flag=0; for(int i=n;i>=0;i--){ if(res[i]) printf("%d",res[i]),flag=1; else if(flag||i==0) printf("0"); } printf("\n"); return 0; }
题意:如题
题解:对两个式子进行化简,运用两次FFT,即可得出答案,注意这种卷积形式的式子,一般都能用FFT去优化
#include <bits/stdc++.h> using namespace std; const int maxn = 2e6+10; const double pi = acos(-1); struct CP { double x, y; CP(){} inline CP(double a, double b):x(a),y(b){} inline CP operator + (const CP&r) const { return CP(x + r.x, y + r.y); } inline CP operator - (const CP&r) const { return CP(x - r.x, y - r.y); } inline CP operator * (const CP&r) const { return CP(x*r.x-y*r.y, x*r.y+y*r.x); } inline CP conj() { return CP(x, -y); } } f[maxn],f1[maxn],g[maxn],t,a[maxn],b[maxn]; int n, m; inline void Swap(CP&a, CP&b) { t = a; a = b; b = t; } inline void FFT(CP*a, int n, int f) { if(n==1) return;int i, j, k; for(i = j = 0; i < n; ++ i) { if(i > j) Swap(a[i], a[j]); for(k = n>>1; (j ^= k) < k; k >>= 1); } for(i = 1; i < n; i <<= 1) { CP wn(cos(pi/i), f*sin(pi/i)); for(j = 0; j < n; j += i<<1) { CP w(1, 0); for(k = 0; k < i; ++ k, w=w*wn) { CP x = a[j+k], y = w*a[i+j+k]; a[j+k] = x+y; a[i+j+k] = x-y; } } } } int main() { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lf",&f[i].x),f1[n-i-1].x=f[i].x; for(int i=1;i<n;i++) g[i].x=1.0/i/i; for(m=2*n,n=1;n<=m;n<<=1); FFT(f,n,1);FFT(f1,n,1);FFT(g,n,1); for(int i=0;i<=n;i++) a[i]=f[i]*g[i],b[i]=f1[i]*g[i]; FFT(a,n,-1);FFT(b,n,-1);m/=2; for(int i=0;i<=n;i++) a[i].x/=n,b[i].x/=n; for(int i=0;i<m;i++) printf("%.3lf\n",a[i].x-b[m-i-1].x); printf("\n"); return 0; }