多項式有多種表示方法,比如係數表示,點值表示。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;
}