FFT
所谓fft,只是一种快速的插值技术,我们知道,朴素的多项式乘法是N^2的。我们又知道,一个多项式可以由N个的点值来表示。那么N个点相乘,可以在O(N)内得出,fft所提供的,只是快速插值和求系数而已。
我们知道 欧拉定理, e的复数次幂满足很多优秀的性质,我们用这些性质快速求值即可。
http://www.gatevin.moe/acm/fft%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/
#include<bits/stdc++.h> #define db double #define fo(i,a,b) for(int i=a;i<=b;i++) #define pi acos(-1) #define N 3378123 #define com rrsb using namespace std; struct com{ //定义复数 db r,i; com(){} com(db a,db b):r(a),i(b){} }; inline com operator + (const com A,const com B) { return com(A.r+B.r,A.i+B.i); } inline com operator - (const com A,const com B) { return com(A.r-B.r,A.i-B.i); } inline com operator * (const com A,const com B) { return com(A.r*B.r-A.i*B.i,A.i*B.r+A.r*B.i); } com a[N],b[N],X,Y; int c[N],R[N],n,m,L; char ch[N]; bool bo; inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9'); return f*x; } inline void fft(com *a,int x){ fo(i,0,n-1) if(i < R[i]) swap(a[i],a[R[i]]); for (int i=1;i<n;i<<=1)// 注意这里的n不是输入的n { com wn(cos(pi/i),x*sin(pi/i)); //wn为旋转因子 for (int j=0;j<n;j+=(i<<1)){//蝴蝶操作减小常熟 com w(1,0); for (int k=0;k<i;k++,w=w*wn) { X=a[j+k]; Y=w*a[j+k+i]; a[j+k]=X+Y; a[i+j+k]=X-Y; } } } if (x==-1) fo(i,0,n-1) a[i].r=a[i].r/n;// 求系数要除n } int main () { //0freopen("a.in","r",stdin); n=read();m=read(); for(int i=0;i<=n;i++)a[i].r=read(); for(int i=0;i<=m;i++)b[i].r=read(); m+=n; for(n = 1;n <= m ;n <<= 1) ++L;// get size fo(i,0,n-1) R[i] = (R[i>>1]>>1)|((i&1)<<(L-1));// 二进制下将位翻转 fft(a,1); fft(b,1);//求点值 fo(i,0,n) a[i]=a[i]*b[i];//点乘 fft(a,-1);//求系数 fo(i,0,m) c[i]=(int)(a[i].r+0.5); fo(i,0,m) printf("%d ",c[i]); return 0; }