FFT模板 [ZJOI2014]力

多項式有多種表示方法,比如係數表示,點值表示。FFT就是實現快速在這兩種表示法之間轉換。多項式在點值時進行多項式乘法是o(n)的,在係數表示法中,多項式相乘中兩個係數序列會進行卷積,但是n^2的,所以轉化成點值進行計算可以優化卷積。

#include<bits/stdc++.h>

using namespace std;
#define pi acos(-1)
struct Complex
{
    double x,y;
    Complex(double _x = 0.0, double _y = 0.0)
    {
        x = _x;
        y = _y;
    }
    Complex operator -(const Complex &b)const
    {
        return Complex(x - b.x, y - b.y);
    }
    Complex operator +(const Complex &b)const
    {
        return Complex(x + b.x, y + b.y);
    }
    Complex operator *(const Complex &b)const
    {
        return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
    }
};

void change(Complex y[],int len)
{
    int i,j,k;
    for(i = 1, j = len / 2; i < len - 1; i++)
    {
        if(i < j) swap(y[i],y[j]);
        k = len / 2;
        while(j >= k)
        {
            j -= k;
            k /= 2;
        }
        if(j < k) j += k;
    }
}
//len必須是2^k
//on==1進行DFT;on==-1進行IDFT
void fft(Complex y[],int len,int on)
{
    change(y,len);
    for(int h = 2; h <= len; h <<= 1)
    {
        Complex wn(cos(-on*2*pi/h),sin(-on*2*pi/h));
        for(int j = 0; j < len; j += h)
        {
            Complex w(1,0);
            for(int k = j; k < j + h / 2; k++)
            {
                Complex u = y[k];
                Complex t = w * y[k + h / 2];
                y[k] = u + t;
                y[k + h / 2] = u - t;
                w = w * wn;
            }
        }
    }
    if(on == -1)
    {
        for(int i = 0; i < len; i++) y[i].x /= (double)len;
    }
}
int n;
Complex a[500005],b[500005],p[500005];
double x[5000005],y[500005];
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%lf",&x[i]);
        a[i]= {x[i],0};
        b[i]= {(double)1/((double)i*(double)i),0};
    }
//    for(int i=1; i<=n; i++)
//        cout<<x[i]<<endl;
    int nn=n;
    for (int j=nn,i=1; (i>>2)<j; i<<=1)
        nn=i;
//    for(int i=0;i<=nn;i++)
//        printf("%.3f %.3f\n",a[i].x,a[i].y);
//    for(int i=0;i<=nn;i++)
//        printf("%.6f %.3f\n",b[i].x,b[i].y);
    fft(a,nn,1),fft(b,nn,1);
    for(int i=0; i<=nn; i++)
        p[i]=a[i]*b[i];
    fft(p,nn,-1);
    for(int i=1; i<=n; i++)
        y[i]=p[i].x;
    a[0]={0,0};
    for(int i=1; i<=n; i++)
        a[i]= {x[n-i+1],0};
    for(int i=n+1; i<=nn; i++)
        a[i]= {0,0};
//            for(int i=0;i<=nn;i++)
//        printf("%d    %.3f %.3f\n",i,a[i].x,a[i].y);
//    for(int i=0;i<=nn;i++)
//        printf("%.6f %.3f\n",b[i].x,b[i].y);
    fft(a,nn,1);
    for(int i=0; i<=nn; i++)
        p[i]=a[i]*b[i];
    fft(p,nn,-1);
    for(int i=1; i<=n; i++)
        x[i]=p[n+1-i].x;
    for(int i=1; i<=n; i++)
    {
        printf("%.6lf\n",y[i]-x[i]);
//        cout<<fixed<<setprecision(6)<<y[i]-x[i]<<" ";
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章