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;
}

 

posted @ 2017-12-01 20:32  泪寒之雪  阅读(671)  评论(0编辑  收藏  举报