【模板】快速傅里叶变换FFT

讲解:
快速傅里叶变换(FFT)详解
公式介绍比较详细。
FFT详解
原理讲解比较清晰。
建议两篇一起看一下。
如果只是在基础应用层面不去深究,FFT还是比较好懂的。


代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define db double
using namespace std;
const int N=5e6+10;
const db pi=acos(-1);
int n,m,l,bin[N];

//誓死不用STL,手打Complex
struct Complex{db real,imag;}a[N],b[N];
typedef Complex cc;
cc operator *(cc x,cc y)
{return (cc){x.real*y.real-x.imag*y.imag,x.real*y.imag+x.imag*y.real};}
cc operator -(cc x,cc y)
{return (cc){x.real-y.real,x.imag-y.imag};}
cc operator +(cc x,cc y)
{return (cc){x.real+y.real,x.imag+y.imag};}
inline void swa(cc &x,cc &y){cc t=x;x=y;y=t;}

inline void FFT(cc *C,int sta)
{
    for(int i=0;i<m;i++) if(i<bin[i]) swa(C[i],C[bin[i]]);
    //迭代
    for(int i=1;i<m;i<<=1){
        cc u=(cc){cos(pi/i),sta*sin(pi/i)};
        for(int j=0;j<m;j+=(i<<1)){
            cc v=(cc){1,0};
            for(int k=0;k<i;k++,v=v*u){
                cc p=C[j+k],q=v*C[i+j+k];
                C[j+k]=p+q;C[i+j+k]=p-q;
            }
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    for(int x,i=0;i<=n;i++){scanf("%d",&x);a[i].real=x;}
    for(int x,i=0;i<=m;i++){scanf("%d",&x);b[i].real=x;}n+=m;
    for(m=1;m<=n;m<<=1) l++;
    for(int i=0;i<m;i++) bin[i]=(bin[i>>1]>>1)|((i&1)<<(l-1));
    FFT(a,1);FFT(b,1);
    for(int i=0;i<m;i++) a[i]=a[i]*b[i];
    FFT(a,-1);
    for(int i=0;i<=n;i++) 
      printf("%d ",(int)(a[i].real/m+0.5));//
    return 0;
}
#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=2e6+10;
const db pi=acos(-1);
int n,m,l,r[N],bin[N],mx;
char ch[N];
struct Complex{db real,imag;}a[N],b[N];
typedef Complex cc;
cc operator *(cc x,cc y)
{return (cc){x.real*y.real-x.imag*y.imag,x.real*y.imag+x.imag*y.real};}
cc operator -(cc x,cc y)
{return (cc){x.real-y.real,x.imag-y.imag};}
cc operator +(cc x,cc y)
{return (cc){x.real+y.real,x.imag+y.imag};}
inline void swa(cc &x,cc &y){cc t=x;x=y;y=t;}

inline void init(cc *C){
    scanf("%s",ch);
    for(int i=0;i<=n;i++) 
      C[n-i].real=(db)(ch[i]^48);
}

inline void FTT(cc *C,int sta)
{
    for(int i=0;i<m;i++) if(i<r[i]) swa(C[i],C[r[i]]);
    for(int i=1;i<m;i<<=1){
        cc u=(cc){cos(pi/i),sta*sin(pi/i)};
        for(int j=0;j<m;j+=(i<<1)){
            cc v=(cc){1,0};
            for(int k=0;k<i;k++,v=v*u){
                cc p=C[j+k],q=v*C[i+j+k];
                C[j+k]=p+q;C[i+j+k]=p-q;
            }
        }
    }
}

int main(){
    scanf("%d",&n);n--;
    init(a);init(b);
    if(n==0){
        printf("%d\n",(int)a[0].real*(int)b[0].real);return 0;
    }
    n<<=1;
    for(m=1;m<=n;m<<=1) l++;
    for(int i=0;i<m;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    FTT(a,1);FTT(b,1);
    for(int i=0;i<m;i++) a[i]=a[i]*b[i];
    FTT(a,-1);
    for(int i=0;i<=n;i++){
        int now=(int)(a[i].real/m+0.5),ty=i;
        while(now){
          bin[ty]+=now%10;
          if(bin[ty]>9){bin[ty+1]+=(bin[ty]/10);bin[ty]=bin[ty]%10;}
          now/=10;
          ty++;
        }
        while(bin[ty]>9){bin[ty+1]+=(bin[ty]/10);bin[ty]=bin[ty]%10;ty++;}
    }
    for(int i=(m<<1);i>=0;i--){if(bin[i]){mx=i;break;}}
    for(int i=mx;i>=0;i--) printf("%d",bin[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80329834