A(x)=a0+a1x+⋯+an−1xn−1=∑j=0n−1ajxj(a0+a1x+⋯+an−1xn−1)(b0+b1x+⋯+bn−1xn−1)=a0b0+(a0b1+a1b0)x+⋯+an−1bn−1x2n−2=∑j=02n−2(∑k=0jakbj−k)xj(aj=bj=0,j≥n)
30.1 多项式的表达
系数表达: (a0,a1,⋯,an−1)
点值表达: {(x0,y0),(x1,y1),⋯,(xn−1,yn−1)}(yk=A(xk),0≤k≤n−1)
求值(系数表达转换为点值表达,
O(n2)
):
霍纳准则:
A(x0)=a0+x0(a1+⋯+x0(an−2+x0an−1)⋯)
插值(点值表达转换为系数表达,
O(n2)
):
拉格朗日公式:
A(x)=∑k=0n−1yk∏j≠k(x−xj)∏j≠k(xk−xj)
30.2 DFT与FFT
wn=1w=w0n,w1n,⋯,wn−1n(wn=e2πi/n)yk=A(wkn)=∑j=0n−1ajwkjn(0≤k≤n−1)
y=(y0,y1,⋯,yn−1) 是 a=(a0,a1,⋯,an−1) 的离散傅里叶变换(DFT)。
n=2kA[0](x)=a0+a2x+⋯+an−2xn/2−1A[1](x)=a1+a3x+⋯+an−1xn/2−1A(x)=A[0](x2)+xA[1](x2)
0≤k≤n/2−1yk=y[0]k+wkny[1]k=A[0](wkn/2)+wknA[1](wkn/2)=A[0](w2kn)+wknA[1](w2kn)=A(wkn)yk+n/2=y[0]k−wkny[1]k=A[0](wkn/2)−wknA[1](wkn/2)=A[0](w2k+nn)+wk+n/2nA[1](w2k+nn)=A(wk+n/2n)
const double PI=3.141592654;
class Complex
{
public:
Complex(double x=0,double y=0):a(x),b(y){}
friend Complex operator+(Complex x,Complex y)
{
return Complex(x.a+y.a,x.b+y.b);
}
friend Complex operator-(Complex x,Complex y)
{
return Complex(x.a-y.a,x.b-y.b);
}
friend Complex operator*(Complex x,Complex y)
{
return Complex(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);
}
double a,b;
};
//递归
vector<Complex> recursiveFFT(vector<Complex> a)
{
int n=a.size();
if(n==1)return a;
Complex wn(cos(2*PI/n),sin(2*PI/n)),w(1,0);
vector<Complex> a0,a1,y0,y1,y;
for(int i=0;i<n;i+=2)a0.push_back(a[i]);
for(int i=1;i<n;i+=2)a1.push_back(a[i]);
y0=recursiveFFT(a0);
y1=recursiveFFT(a1);
for(int k=0;k<=n/2-1;++k)
{
y[k]=y0[k]+w*y1[k];
y[k+n/2]=y0[k]-w*y1[k];
w=w*wn;
}
return y;
}
T(n)=2T(n/2)+Θ(n)=Θ(nlogn)
30.3 高效FFT实现
//蝴蝶操作
for(int k=0;k<=n/2-1;++k)
{
Complex t=w*y1[k];
y[k]=y0[k]+t;
y[k+n/2]=y0[k]-t;
w=w*wn;
}
//位逆序置换
int rev(int k,int n)
{
int k0=0,m=log((double)n)/log((double)2);
for(int j=0;j<m;++j)
{
if(k&(1<<j))k0+=(1<<(m-1-j));
}
return k0;
}
void bitReverseCopy(vector<Complex> a,vector<Complex> &A)
{
int n=a.size();
for(int k=0;k<=n-1;++k)A[rev(k,n)]=a[k];
}
//迭代
vector<Complex> iterativeFFT(vector<Complex> a)
{
vector<Complex> A;
bitReverseCopy(a,A);
int n=a.size();
for(int s=1;(1<<s)<=n;++s)
{
int m=(1<<s);
Complex wm(cos(2*PI/m),sin(2*PI/m));
for(int k=0;k<=n-1;k+=m)
{
Complex w(1,0);
for(int j=0;j<=m/2-1;++j)
{
Complex u=A[k+j],t=w*A[k+j+m/2];
A[k+j]=u+t;
A[k+j+m/2]=u-t;
w=w*wm;
}
}
}
return A;
}