BZOJ 2194: 快速傅立叶之二

来源:互联网 发布:linux网络工程师培训 编辑:程序博客网 时间:2024/05/18 01:22

这道题体现了快速傅里叶变换最重要的应用:求卷积。所谓卷积根本没有必要去看百度上那晦涩难懂的定义,只要拿多项式联想一下就好了,我们求快速傅里叶变换实际上就是求出了两个多项式相乘之后对应次数未知数的系数,这就叫做两个多项式的卷积,那么什么样的多项式能用的上卷积呢,就是要求的东西下标相加之后为定值,用FFT求完之后的结果就是每一个定值的系数。就像这道题,虽然i+i-k并不是一个定值,但是如果我们将a数组倒过来,每个i变为n-i的话就会发现原式变为了n-k,这样求出来的卷积第n-k位对应的就是c[k]的值,倒着输出就好了。

#include<cstdio>#include<cstdlib>#include<iostream>#include<iomanip>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>using namespace std;struct cpx{    double a,b;    cpx(double _=0.0,double __=0.0):a(_),b(__){}    cpx operator +(cpx x) {return cpx(a+x.a,b+x.b);}    cpx operator -(cpx x) {return cpx(a-x.a,b-x.b);}    cpx operator *(cpx x) {return cpx(a*x.a-b*x.b,a*x.b+b*x.a);}}a[300000],b[300000],c[300000];const double DFT=2.0;const double IDFT=-2.0;double trans_form;const double pi=acos(-1);int len;int pos[300000];void init(){    for(int i=0;i<len;i++)    {        pos[i]=pos[i>>1]>>1;        if(i&1) pos[i]|=(len>>1);    }}void trans(cpx x[]){    for(int i=0;i<len;i++) if(i<pos[i]) swap(x[i],x[pos[i]]);    for(int i=2;i<=len;i<<=1)    {        int step=i>>1;        cpx wm(cos(2*pi/(double)i),sin(trans_form*pi/(double)i));        for(int j=0;j<len;j+=i)        {            int limit=j+step;            cpx ww(1,0);            for(int k=j;k<limit;k++)            {                cpx a=x[k];                cpx b=x[k+step]*ww;                ww=ww*wm;                x[k]=a+b;                x[k+step]=a-b;            }        }    }    if(trans_form==IDFT) for(int i=0;i<len;i++) x[i].a/=(double)len;}int main(){    int n;    scanf("%d",&n);    len=1;    while(len<(n<<1)) len<<=1;    init();    for(int i=1;i<=n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        a[n-i].a=x;        b[i-1].a=y;    }    trans_form=DFT;    trans(a);    trans(b);    for(int i=0;i<len;i++) c[i]=a[i]*b[i];    trans_form=IDFT;    trans(c);    int top=0;    for(int i=n-1;i>=0;i--) printf("%d\n",int(c[i].a+0.5));    return 0;}
0 0