[学习]快速傅里叶变换

快速傅里叶变换用于加速多项式的乘法,复杂度O(nlogn),例题:http://uoj.ac/problem/34

详解:https://www.cnblogs.com/RabbitHu/p/FFT.html

模板:

#include<bits/stdc++.h>
#define PI acos(-1.0)
using namespace std;

struct Complex{
    double real,img;
    Complex(const double &real=0.0,const double &img=0.0):real(real),img(img){}
    Complex operator + (const Complex &c) const {return Complex(real+c.real,img+c.img); }
    Complex operator - (const Complex &c) const {return Complex(real-c.real,img-c.img); }
    Complex operator * (const Complex &c) const {return Complex(real*c.real-img*c.img,real*c.img+img*c.real); }
}a[100005*4],b[100005*4],omg[100005*4],inv[100005*4];//长度为fn的大小

void init(int n){
    for(int i = 0; i < n; i++){
        omg[i] = Complex(cos(2 * PI * i / n), sin(2 * PI * i / n));
        inv[i] = Complex(cos(2 * PI * i / n), -1.0*sin(2.0 * PI * i / n));
    }
}

void fft(Complex *a,int n,Complex *omg){
    int lim = 0;
    while((1 << lim) < n) lim++;
    for(int i = 0; i < n; i++){
        int t = 0;
        for(int j = 0; j < lim; j++)
            if((i >> j) & 1) t |= (1 << (lim - j - 1));
        if(i < t) swap(a[i], a[t]);
    }

    for(int l = 2; l <= n; l *= 2){
        int m = l / 2;
        for(Complex *p = a; p != a + n; p += l)
        for(int i = 0; i < m; i++){
            Complex t = omg[n / l * i] * p[i + m];
            p[i + m] = p[i] - t;
            p[i] = p[i] + t;
        }
    }
}

int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++) scanf("%lf",&a[i].real);
    for(int i=0;i<=m;i++) scanf("%lf",&b[i].real);

    int fn=1;//fn-1次多项式,fn=2^k
    while(fn<=n+m) fn<<=1;
    init(fn);

    fft(a,fn,omg);
    fft(b,fn,omg);

    for(int i=0;i<fn;i++) a[i]=a[i]*b[i];
    fft(a,fn,inv);

    for(int i=0;i<=n+m;i++) printf("%d ",int(a[i].real/fn+0.5));
    puts("");

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lllxq/p/11135155.html
今日推荐