In solitute,where we are|

Luisvacson

园龄:3年6个月粉丝:5关注:0

浅谈快速傅里叶变换(FFT)

多项式乘法

我们定义两个次多项式F(x),G(x),有:

F(x)=fi×xiG(x)=gi×xi

其中{fi},{gi}表示两个多项式的系数

显然当一个多项式的系数被确定后这个多项式就被确定了,我们把这称之为多项式的系数表达

两个多项式可以相乘得到一个结果,比如:

(x2+2x+3)(2x2+3x+4)=2x4+3x3+4x2+4x3+6x2+8x+6x2+9x+12=2x4+7x3+16x2+17x+12

我们令H(x)=F(x)×G(x),因为H(x)中的xk只能由F(x)中的xiG(x)中的xki相乘得到,所以我们有:

hk=i=0kfi×gki

同样,这里的{hi}表示H(x)的系数

可以观察到按照这个定义式暴力计算的复杂度是O(n2)级别的,很多时候难以接受,所以我们需要一种高效的算法

FFT

快速傅里叶变换(Fast Fourier Transfromation)简称FFT,可以实现在O(nlogn)时间里计算多项式乘法

对于一个多项式F(x),我们把它看作一个关于x的函数,显然可以得到它的图像。带入一个值x0便可以得到一个对应的y0(x0,y0)便构成了一个有序数对表示点的坐标

结论:n个点的坐标可以唯一确定一个n1次函数

感性证明:

对于一个n1次函数,我们带入n个值得到有n个方程的方程组,此时有n个未知数(系数),解方程即可求出系数,系数确定函数(多项式)也随之确定

所以当我们有了n对有序实数时,原多项式F(x)的表达式就唯一确定,这也就意味着我们可以用n个有序实数对等效表示一个多项式,我们将这一组有序实数对称为这个多项式的点值表达

我们现在给出两个多项式F(x),G(x),令H(x)=F(x)×G(x)

我们将数列{x0,x1x2n}分别带入F(x),G(x),得到两组有序数对(x0,y0),(x1,y1)(x2n,y2n)(x0,y0),(x1,y1)(x2n,y2n)

显然F(x0)×G(x0)=y0×y0,而这个值就等于H(x0)

将两组有序实数对都这样相乘,我们会得到一组新的有序实数对(x0,y0),(x1,y1)(x2n,y2n),而这组有序实数对就和H(x)对应,如此便可以求出H(x)的系数,从而确定H(x)的表达式。这就是FFT的核心思想:

将多项式转变为点值表达,相乘求出乘积多项式的点值表达,最后再转变为系数表达

将系数表达转化为点值表达的过程称为DFT,将点值表达转化为系数表达的过程称为IDFT

复数

我们定义形如a+bi的数为复数,其中i=1。我们定义a为该复数的实部,bi为该复数的虚部

所有实数都可以在一条坐标轴上找到唯一一个对应的点,我们再添加一条竖着的数轴表示虚数,即可使所有复数同这个新形成的平面直角坐标系里的每个点一一对应:

image

比如上图中这个点A即可表示复数3+2i

复数可以进行四则运算:

复数相加:实部和虚部分别相加

如:(3+2i)+(5+4i)=8+6i

复数相减:取相反数再相加

复数相乘:像多项式一样相乘

如:

(1)(3+2i)(5+4i)=15+12i+10i+8i2=7+22i

注意这里i2=1

复数相除在FFT里暂时用不到,故暂不说明

这里我们需要注意复数相乘在刚才的平面直角坐标系里面的体现:

image

(该图来自command_block大佬/bx/bx)

我们定义该坐标系中一个点到原点的距离为这个复数的模长,这条连线与x轴正半轴的夹角为这个复数的辐角

观察我们可以发现:复数相乘,模长相乘,辐角相加,证明很简单,代入计算即可

单位根

我们做DFT选择带入的值时,一般都会考虑一些常见好算的整数带入。理论上DFT的时候可以带入任意值,但是带入整数后的IDFT过程不好处理(详细证明见后),而傅里叶想到了带入单位根

我们定义方程xn=1复数解n次单位根

根据“复数相乘,模长相乘,辐角相加”可以得到所有单位根的模长都是1,换句话说就是所有单位根都在单位圆上。因此模长不会对结果造成影响,我们只考虑辐角

我们画出一个单位圆:

image

容易发现辐角大小为0,1n×2π,2n×2πn1n×2π的复数都是n次单位根
image

由代数基本定理:n次方程在复数域内有且只有n个根可知以上n个复数即为所有单位根

显然所有单位根平分单位圆

我们用ωni来表示逆时针看第i个单位根,比如ωn0就表示(1,0)这个点,所有n次单位根为ωn0,ωn1ωnn1

当然我们也可以定义ωnk为顺时针旋转kn个圆周得到的单位根

ωnk的辐角为θ,则该坐标显然为(cosθ,sinθ)

单位根有几个性质:

1.ωn0=1对于任意n都成立

显然

2.(ωn1)k=ωnk

证明:

根据“复数相乘,模长相乘,辐角相加”可知,每次乘上一个ωn1就相当于逆时针转动了1n个圆周,转动k次就到达了第k个单位根

3.ωni×ωnj=ωni+j

证明:

ωni×ωnj=(ωn1)i×(ωn1)j=(ωn1)i+j=ωni+j

4.(ωni)j=ωnij

证明:

(ωni)j=ωni×ωni×ωni=ωni+i++i=ωnij

5.ωpnpi=ωni,其中p为常数

证明:

由于所有单位根平分单位圆,所以ωpnpi的辐角就是pipn×2π=in×2π,与ωni辐角相同

6.若n为偶数,则ωni+n/2=ωni

证明:

ωni+n/2=ωni×ωnn/2,显然ωnn/2辐角为π,乘上它相当于旋转π,到达关于原点的对称点,此时显然结果为ωni,不懂可以画图看看

DFT

我们将一个n1次多项式F(x)(这里我们让n=2k,kZ,若不成立则在高位补0)按照奇偶分成两块:

F(x)=(f0×x0+f2×x2++fn2×xn2)+(f1×x1+f3×x3++fn1×xn1)

我们再定义两个多项式FL(x),FR(x):

FL(x)=f0×x0+f2×x1+f4×x2++fn2×xn/21FR(x)=f1×x0+f3×x1+f5×x2++fn1×xn/21

显然有:

F(x)=FL(x2)+xFR(x2)

我们将ωnk(k<n2)带入上式:

(2)F(ωnk)=FL((ωnk)2)+ωnkFR((ωnk)2)=FL(ωn2k)+ωnkFR(ωn2k)=FL(ωn/2k)+ωnkFR(ωn/2k)

我们再把ωnk+n/2(k<n2)代入上式:

(3)F(ωnk+n/2)=FL((ωnk+n/2)2)+ωnk+n/2FR((ωnk+n/2)2)=FL(ωn2k+n)ωnkFR(ωn2k+n)=FL(ωn2k)ωnkFR(ωn2k)=FL(ωn/2k)ωnkFR(ωn/2k)

发现什么?这两个式子只有一个符号的差距

所以说如果我们知道了FL(x)FR(x)ωn0,ωn1ωnn1的点值表示,代入上式即可在O(n)时间里求出F(x)的点值表示

我们再次观察上述过程,看到第一步:

我们将一个n1次多项式F(x)(这里n=2k,kZ)按照奇偶分成两块

这个过程是什么?分治

所以我们同样可以对FL(x)FR(x)进行分治,递归处理,直到只剩下一项

Code:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 100005

const double pi = acos(-1);
class Complex {
   public:
    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    double x, y;
    Complex operator+(Complex const &B) const {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator-(Complex const &B) const {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator*(Complex const &B) const {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
} f[MAXN], tp[MAXN];

void dft(Complex *f, int len) {
    if (len == 1) return;
    Complex *fl = f, *fr = f + (len >> 1);
    int i;

    for (i = 0; i < len; ++i) tp[i] = f[i];
    for (i = 0; i < (len >> 1); ++i) {
        fl[i] = tp[i << 1];
        fr[i] = tp[i << 1 | 1];
    }

    dft(fl, len >> 1);
    dft(fr, len >> 1);

    Complex w(cos(2 * pi / len), sin(2 * pi / len)), buf(1, 0);
    for (i = 0; i < (len >> 1); ++i) {
        tp[i] = fl[i] + buf * fr[i];
        tp[i + (len >> 1)] = fl[i] - buf * fr[i];
        buf = buf * w;
    }

    for (i = 0; i < len; ++i) f[i] = tp[i];
}

IDFT

IDFT就是把点值表示再转化为系数表示,也就是DFT的逆过程

我们令DFT(F)得到的点值数列为G,那么有:

fk=1ni=0n1gi(ωnk)i

证明:

显然根据DFT定义有:

gk=i=0n1fi(ωnk)i

所以有:

(4)i=0n1gi(ωnk)i=i=0n1j=0n1fj(ωni)j(ωnk)i=i=0n1j=0n1fjωnijik=i=0n1j=0n1fjωni(jk)

我们分类讨论:

j=k

则有:

(5)i=0n1gi(ωnk)i=i=0n1fkωn0=nfk

jk

p=jk

则有:

(6)i=0n1gi(ωnk)i=i=0n1fk+pωnip=nfk+pωnpi=0n1ωni

S=i=0n1ωni

则有ωn1S=i=1nωni

所以有:

(ωn11)S=ωnnωn0S=ωnnωn0ωn11=0

所以(6)式的值为0,对结果不产生贡献

综上可知,(4)式的值为nfk,故原等式成立

由此我们再代入ωn0,ωn1ωnn+1即可完成IDFT

此时我们再反观一开始的问题:为什么要代入单位根?因为单位根的性质使得DFTIDFT变得十分简单,代入别的数难以达到这个效果

这个IDFT的过程可以被理解为范德蒙德矩阵求逆,这也衍生出单位根反演,在此不多做赘述

Code:(和DFT几乎一样)

#include <bits/stdc++.h>
using namespace std;
#define MAXN 100005

const double pi = acos(-1);
class Complex {
   public:
    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    double x, y;
    Complex operator+(Complex const &B) const {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator-(Complex const &B) const {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator*(Complex const &B) const {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
} f[MAXN], tp[MAXN];

void idft(Complex *f, int len) {
    if (len == 1) return;
    Complex *fl = f, *fr = f + (len >> 1);
    int i;

    for (i = 0; i < len; ++i) tp[i] = f[i];
    for (i = 0; i < (len >> 1); ++i) {
        fl[i] = tp[i << 1];
        fr[i] = tp[i << 1 | 1];
    }

    idft(fl, len >> 1);
    idft(fr, len >> 1);

    Complex w(cos(2 * pi / len), -sin(2 * pi / len)), buf(1, 0);
    for (i = 0; i < (len >> 1); ++i) {
        tp[i] = fl[i] + buf * fr[i];
        tp[i + (len >> 1)] = fl[i] - buf * fr[i];
        buf = buf * w;
    }

    for (i = 0; i < len; ++i) f[i] = tp[i];//除以n的事放到主函数里面做
}

综合在一起,我们就得到了最初版本的FFT

#include <bits/stdc++.h>
using namespace std;
#define MAXN 100005

const double pi = acos(-1);
class Complex {
   public:
    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    double x, y;
    Complex operator+(Complex const &B) const {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator-(Complex const &B) const {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator*(Complex const &B) const {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
} f[MAXN], a[MAXN], b[MAXN], tp[MAXN];

void dft(Complex *f, int len) {
    if (len == 1) return;
    Complex *fl = f, *fr = f + (len >> 1);
    int i;

    for (i = 0; i < len; ++i) tp[i] = f[i];
    for (i = 0; i < (len >> 1); ++i) {
        fl[i] = tp[i << 1];
        fr[i] = tp[i << 1 | 1];
    }

    dft(fl, len >> 1);
    dft(fr, len >> 1);

    Complex w(cos(2 * pi / len), sin(2 * pi / len)), buf(1, 0);
    for (i = 0; i < (len >> 1); ++i) {
        tp[i] = fl[i] + buf * fr[i];
        tp[i + (len >> 1)] = fl[i] - buf * fr[i];
        buf = buf * w;
    }

    for (i = 0; i < len; ++i) f[i] = tp[i];
}

void idft(Complex *f, int len) {
    if (len == 1) return;
    Complex *fl = f, *fr = f + (len >> 1);
    int i;

    for (i = 0; i < len; ++i) tp[i] = f[i];
    for (i = 0; i < (len >> 1); ++i) {
        fl[i] = tp[i << 1];
        fr[i] = tp[i << 1 | 1];
    }

    idft(fl, len >> 1);
    idft(fr, len >> 1);

    Complex w(cos(2 * pi / len), -sin(2 * pi / len)), buf(1, 0);
    for (i = 0; i < (len >> 1); ++i) {
        tp[i] = fl[i] + buf * fr[i];
        tp[i + (len >> 1)] = fl[i] - buf * fr[i];
        buf = buf * w;
    }

    for (i = 0; i < len; ++i) f[i] = tp[i];
}

int n, m;
signed main() {
    scanf("%d%d", &n, &m);
    int i;

    for (i = 0; i <= n; ++i) scanf("%lf", &a[i].x);
    for (i = 0; i <= m; ++i) scanf("%lf", &b[i].x);
    for (m += n, n = 1; n <= m; n <<= 1)
        ;

    dft(a, n), dft(b, n);
    for (i = 0; i < n; ++i) f[i] = a[i] * b[i];
    idft(f, n);
    for (i = 0; i <= m; ++i) printf("%d ", (int)(f[i].x / n + 0.5));//在这里除以n
    return 0;
}

由于DFTIDFT的代码差不多,所以我们可以把他们写到一起:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 5000005

const double pi = acos(-1);
class Complex {
   public:
    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    double x, y;
    Complex operator+(Complex const &B) const {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator-(Complex const &B) const {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator*(Complex const &B) const {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
} f[MAXN], a[MAXN], b[MAXN], tp[MAXN];

void fft(Complex *f, int len, int flag) {
    if (len == 1) return;
    Complex *fl = f, *fr = f + (len >> 1);
    int i;

    for (i = 0; i < len; ++i) tp[i] = f[i];
    for (i = 0; i < (len >> 1); ++i) {
        fl[i] = tp[i << 1];
        fr[i] = tp[i << 1 | 1];
    }

    fft(fl, len >> 1, flag);
    fft(fr, len >> 1, flag);

    Complex w(cos(2 * pi / len), flag * sin(2 * pi / len)), buf(1, 0);
    for (i = 0; i < (len >> 1); ++i) {
        tp[i] = fl[i] + buf * fr[i];
        tp[i + (len >> 1)] = fl[i] - buf * fr[i];
        buf = buf * w;
    }

    for (i = 0; i < len; ++i) f[i] = tp[i];
}

int n, m;
signed main() {
    scanf("%d%d", &n, &m);
    int i;

    for (i = 0; i <= n; ++i) scanf("%lf", &a[i].x);
    for (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 (i = 0; i < n; ++i) f[i] = a[i] * b[i];
    fft(f, n, -1);
    for (i = 0; i <= m; ++i) printf("%d ", (int)(f[i].x / n + 0.5));
    return 0;
}

以上代码可以通过洛谷P3803 【模板】多项式乘法(FFT)

优化

我们可以观察到上述代码使用递归实现FFT的速度并不尽如人意,所以我们要优化

首先观察分治的过程:
image

我们发现分治到最后某个数的下标就是原来的下标在二进制意义下翻转的结果,所以我们可以用一个类似数位dp的东西来预处理出每个数在分治序列中的下标,从而避免了递归处理

具体地说,我们令ri为递归后原数列中fi所在的位置。我们把i拆成最后一位和前面所有位两部分,显然ri就是最后一位加上前面所有位的翻转

所以有:

r[i] = (r[i >> 1] >> 1) | ((i & 1) << (len - 1))

同时我们观察这部分代码:

for (i = 0; i < (len >> 1); ++i) {
    tp[i] = fl[i] + buf * fr[i];
    tp[i + (len >> 1)] = fl[i] - buf * fr[i];
    buf = buf * w;
}

for (i = 0; i < len; ++i) f[i] = tp[i];

拷贝数组的常数会比较大,所以我们可以一边做一边拷贝:

for (i = 0; i < (len >> 1); ++i) {
    Complex t = buf * fr[i];
    f[i + (len >> 1)] = fl[i] - t;
    f[i] = fl[i] + t;//注意赋值的顺序
    buf = buf * w;
}

同时还可以迭代实现:

void fft(Complex *f, int flag) {
    int i, j, k;
    for (i = 0; i < n; ++i)
        if (i < r[i]) swap(f[i], f[r[i]]);//预处理位置

    for (int len = 2; len <= n; len <<= 1) {//由小到大合并而不是由大到小递归
        Complex w(cos(2 * pi / len), flag * sin(2 * pi / len));
        for (j = 0; j < n; j += len) {
            Complex buf(1, 0);
            for (k = j; k < j + (len >> 1); ++k) {
                Complex t = buf * f[k + (len >> 1)];
                f[k + (len >> 1)] = f[k] - t;
                f[k] = f[k] + t;
                buf = buf * w;
            }
        }
    }
}

完整版(也是最常见的)FFT代码:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 5000005

const double pi = acos(-1);
class Complex {
   public:
    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    double x, y;
    Complex operator+(Complex const &B) const {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator-(Complex const &B) const {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator*(Complex const &B) const {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
} f[MAXN], a[MAXN], b[MAXN], tp[MAXN];

int n, m;
int r[MAXN];
void fft(Complex *f, int flag) {
    int i, j, k;
    for (i = 0; i < n; ++i)
        if (i < r[i]) swap(f[i], f[r[i]]);

    for (int len = 2; len <= n; len <<= 1) {
        Complex w(cos(2 * pi / len), flag * sin(2 * pi / len));
        for (j = 0; j < n; j += len) {
            Complex buf(1, 0);
            for (k = j; k < j + (len >> 1); ++k) {
                Complex t = buf * f[k + (len >> 1)];
                f[k + (len >> 1)] = f[k] - t;
                f[k] = f[k] + t;
                buf = buf * w;
            }
        }
    }
}

signed main() {
    scanf("%d%d", &n, &m);
    int i, cnt = 0;

    for (i = 0; i <= n; ++i) scanf("%lf", &a[i].x);
    for (i = 0; i <= m; ++i) scanf("%lf", &b[i].x);
    for (m += n, n = 1; n <= m; n <<= 1) ++cnt;

    for (i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (cnt - 1));

    fft(a, 1), fft(b, 1);
    for (i = 0; i < n; ++i) f[i] = a[i] * b[i];
    fft(f, -1);
    for (i = 0; i <= m; ++i) printf("%d ", (int)(f[i].x / n + 0.5));
    return 0;
}

image

可以看到优化后效果还是很明显的

例题

洛谷P1919 【模板】A*B Problem升级版

给出两个正整数A,B,求A×B的值
1A,B101000000

我们可以把一个n位正整数看成一个n1次的x=10的多项式,然后直接乘起来就可以了

#include <bits/stdc++.h>
using namespace std;
#define MAXN 3000005

const double pi = acos(-1);
class Complex {
   public:
    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    double x, y;
    Complex operator+(Complex const &B) const {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator-(Complex const &B) const {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator*(Complex const &B) const {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
} f[MAXN], a[MAXN], b[MAXN], tp[MAXN];

int n, m;
int r[MAXN];
void fft(Complex *f, int flag) {
    int i, j, k;
    for (i = 0; i < n; ++i)
        if (i < r[i]) swap(f[i], f[r[i]]);

    for (int len = 2; len <= n; len <<= 1) {
        Complex w(cos(2 * pi / len), flag * sin(2 * pi / len));
        for (j = 0; j < n; j += len) {
            Complex buf(1, 0);
            for (k = j; k < j + (len >> 1); ++k) {
                Complex t = buf * f[k + (len >> 1)];
                f[k + (len >> 1)] = f[k] - t;
                f[k] = f[k] + t;
                buf = buf * w;
            }
        }
    }
}

int idx = 0;
int ans[MAXN];
char s1[MAXN], s2[MAXN];
signed main() {
    scanf("%s%s", s1, s2);
    int i, cnt = 0;
    n = strlen(s1), m = strlen(s2);
    --n, --m;

    for (i = n; i >= 0; --i) a[n - i].x = (s1[i] - 48) * 1.0;
    for (i = m; i >= 0; --i) b[m - i].x = (s2[i] - 48) * 1.0;

    for (m += n, n = 1; n <= m; n <<= 1) ++cnt;

    for (i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (cnt - 1));

    fft(a, 1), fft(b, 1);
    for (i = 0; i < n; ++i) f[i] = a[i] * b[i];
    fft(f, -1);

    for (i = 0; i <= n; ++i) {
        ans[i] += (int)(f[i].x / n + 0.5);
        if (ans[i] >= 10) {
            if (i == n) ++n;
            ans[i + 1] += ans[i] / 10;
            ans[i] %= 10;
        }
    }

    while (!ans[n] && n) --n;
    ++n;
    while (n--) printf("%d", ans[n]);
    return 0;
}

[ZJOI2014]力

给出n个数{qi}Fj=i<jqi×qj(ij)2i>jqi×qj(ij)2,Ei=Fiqi,对于每个1in求出Ei
1n105

(7)Ej=Fjqj=i<jqi×qj(ij)2i>jqi×qj(ij)2qj=i<jqi(ij)2i>jqi(ij)2=i<jqi(ji)2i>jqi(ij)2

fi=qi,gi=1i2

(8)Ej=i=0j1figjii=j+1nfigij

我们把序列翻转一下,令新序列的fi=fi

(9)Ej=i=0j1figjii=0j1figji

发现前后两个和式都是卷积的形式,直接FFT即可

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000005

const double pi = acos(-1);
class Complex {
   public:
    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    double x, y;
    Complex operator+(Complex const &B) const {
        return Complex(x + B.x, y + B.y);
    }
    Complex operator-(Complex const &B) const {
        return Complex(x - B.x, y - B.y);
    }
    Complex operator*(Complex const &B) const {
        return Complex(x * B.x - y * B.y, x * B.y + y * B.x);
    }
} f1[MAXN], f2[MAXN], a[MAXN], b[MAXN], tp[MAXN];

int n, m;
int r[MAXN];
void fft(Complex *f, int flag) {
    int i, j, k;
    for (i = 0; i < n; ++i)
        if (i < r[i]) swap(f[i], f[r[i]]);

    for (int len = 2; len <= n; len <<= 1) {
        Complex w(cos(2 * pi / len), flag * sin(2 * pi / len));
        for (j = 0; j < n; j += len) {
            Complex buf(1, 0);
            for (k = j; k < j + (len >> 1); ++k) {
                Complex t = buf * f[k + (len >> 1)];
                f[k + (len >> 1)] = f[k] - t;
                f[k] = f[k] + t;
                buf = buf * w;
            }
        }
    }
}

signed main() {
    scanf("%d", &n);
    int i, cnt = 0;

    for (i = 1; i <= n; ++i) {
        scanf("%lf", &tp[i].x);
        a[i].x = (double)(1.0 / i / i);
        b[i].x = tp[i].x;
    }
    reverse(tp + 1, tp + n + 1);

    int t = n;
    for (n = 1; n < (t << 1); n <<= 1) ++cnt;

    for (i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (cnt - 1));

    fft(a, 1), fft(b, 1), fft(tp, 1);
    for (i = 0; i <= n; ++i) {
        f1[i] = a[i] * b[i];
        f2[i] = a[i] * tp[i];
    }

    fft(f1, -1), fft(f2, -1);
    for (i = 1; i <= t; ++i) {
        printf("%lf\n", (f1[i].x / n) - (f2[t - i + 1].x / n));
    }

    return 0;
}

posted @   Luisvacson  阅读(375)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起