[Algorithm template] FFT- fast Fourier transform

[Algorithm template] FFT- fast Fourier transform

Thank ZYW get together for us to explain FFT ~

Thinking

I'm lazy, ideas and proven part of the directly attached link:

rvalue

LSJ-FFT with NTT basis

Code

The main idea is to use a special unit root properties (half power after the n-th unit root in front of the value is equal to half power). Just because formulas odd powers but also proposed a \ (\ omega_n ^ k \) , this thing is just to take a counter-like (ie symmetry: \ (\ omega_n ^ k = - \ omega_n ^ {k + \ {2} {n-FRAC}} \) ).

FFT recursion:

#include <cstdio>
#include <cmath>
using namespace std;
const int maxn=2e6+10;
const double pi=acos(-1.0);
struct comp{
    double a,b;
};
comp operator +(comp a,comp b){return (comp){a.a+b.a,a.b+b.b};}
comp operator -(comp a,comp b){return (comp){a.a-b.a,a.b-b.b};}
comp operator *(comp a,comp b){return (comp){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a};}
void fft(int l,comp *a,int f)
{
    if(l==1) return;
    comp a1[l>>1],a2[l>>1];
    for(int i=0;i<l;i+=2)
    {
        a1[i>>1]=a[i];
        a2[i>>1]=a[i+1];
    }
    fft(l>>1,a1,f); fft(l>>1,a2,f);
    comp wn=(comp){cos(2*pi/l),f*sin(2*pi/l)},w=(comp){1,0};
    for(int i=0;i<(l>>1);i++,w=w*wn)
    {
        a[i]=a1[i]+w*a2[i];
        a[i+(l>>1)]=a1[i]-w*a2[i];
    }
}
comp a[maxn],b[maxn];
int main ()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++) scanf("%lf",&a[i].a);
    for(int i=0;i<=m;i++) scanf("%lf",&b[i].a);
    int l=1; while(l<=n+m) l<<=1;
    fft(l,a,1); fft(l,b,1);
    for(int i=0;i<l;i++) a[i]=a[i]*b[i];
    fft(l,a,-1);
    for(int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].a/l+0.5));
    return 0;
}

Because of its low operating efficiency. We generally use an iterative FFT.

FFT iteration:

#include <cstdio>
#include <cmath>
#include <iostream> 
using namespace std;
const int maxn=4*1e6+10;
const double pi=acos(-1.0);
struct comp{
    double a,b;
};
comp operator +(comp a,comp b){return (comp){a.a+b.a,a.b+b.b};}
comp operator -(comp a,comp b){return (comp){a.a-b.a,a.b-b.b};}
comp operator *(comp a,comp b){return (comp){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a};}
int rev[maxn],rp;
void get_rev(int l)//l为位数,rev[i]代表i的二进制表示颠倒(二进制位有l位,不足补0) 
{
    for(int i=1;i<(1<<l);i++)
    rev[i]=(rev[i>>1]>>1)|((1&i)<<l-1);
}
void fft(int len,comp *a,int f)
{
    for(int i=1;i<len;i++)
    if(rev[i]>i) swap(a[rev[i]],a[i]);
    for(int l=2;l<=len;l<<=1)//区间长度 
    {
        comp wn=(comp){cos(2*pi/l),f*sin(2*pi/l)};  
        for(int i=0;i+l<=len;i+=l)
        {
            comp w=(comp){1,0};
            for(int k=i;k<i+(l>>1);k++,w=w*wn)
            {
                comp t=w*a[k+(l>>1)],tmp=a[k];
                a[k]=tmp+t;
                a[k+(l>>1)]=tmp-t;
            }
        }
    }            
}
//a[i]表示当x=单位根的i次方时y的值 
comp a[maxn],b[maxn];
int main ()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++) scanf("%lf",&a[i].a);
    for(int i=0;i<=m;i++) scanf("%lf",&b[i].a);
    int l=1,cnt=0; while(l<=n+m) l<<=1,cnt++;
    get_rev(cnt);
    fft(l,a,1); fft(l,b,1);
    for(int i=0;i<l;i++) a[i]=a[i]*b[i];
    fft(l,a,-1);
    for(int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].a/l+0.5));
    return 0;
}

Guess you like

Origin www.cnblogs.com/GavinZheng/p/12037097.html