FFT入门+入门题目


入门博客:十分简明易懂的FFT(快速傅里叶变换)

个人理解:该算法用来加速多项式乘法,卷积操作,生成函数的乘积,时间复杂度o(nlogn),关键在于系数表达式到点值表达式的转换(DFT),以及IDFT的优化,  

     同时应用了n次单位根的优越性,FFT(a,n,1),FFT(a,n,-1)即可在点值与系数之间进行转换。

注意细节:1.FFT因应用了复数,存在着误差,不适用取模操作

     2.多项式相乘的时候,注意n的取值,一定为2的幂指数倍

欠缺:应用不够熟练,对什么时候该建模,什么时候对算式进行化简尚未很清晰,需要多做题目

入门题目:

1.P3803 【模板】多项式乘法(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;
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;
}
View Code

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;
}
View Code

3.bzoj3527: [Zjoi2014]力

题意:如题

题解:对两个式子进行化简,运用两次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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/vainglory/p/10439859.html