Fast Fourier Transform (FFT) and polynomial algorithm study notes

References: Menci's blog

Preface:

A recent study generating function, but unfortunately I found that if I do not learn \ (O (nlogn) \) polynomial algorithm, then what title can not do qwq

So he rolled to learn the FFT

In fact, writing sucks, mainly to see for himself

I'm not as if the whole room would this stuff up

definition

Polynomial

The form \ (F (x) = \ sum \ limits_ {i = 0} ^ na_ix ^ i \) persimmon is a polynomial, that polynomial is its maximum number of \ (n-\)

Polynomial representation

Coefficient representation

It is to use \ (\ {a_1, a_2, a_i, ..., a_n \} \) to represent the polynomial.

Point value notation

Is to use n points \ ((x_i, y_i) \ ) to represent the polynomial.

For any point \ (F (x_i) = y_i \)

This makes it possible to determine uniquely easy to know a polynomial.

Denotes a switching point value representation method may be used as interpolation coefficients.

Polynomial multiplication

Defined polynomial \ (A (x) = \ sum \ limits_ {i = 0} ^ na_ix ^ i \) a polynomial \ (B (x) = sum \ limits_ {i = 0} ^ nb_ix ^ i \ \) product for

\(C(x)=\sum\limits_{k=0}^{2n}(\sum\limits_{i+j=k}{a_ib_j})x^k\)

Less than zero padding bits to the high.

Time complexity \ (O (n ^ 2) \)

If a point value corresponding directly to the notation \ (y_i \) take up on it.

Time complexity \ (O (n) \)

Well see here you will find a very good method is to use expressed strong point value is multiplied by law, the complexity of the \ (O (the n-) \) , finish this blog.

However, we usually use the polynomial coefficients generally form.

It is very unfortunate to tell you,

The point value / conversion coefficients into coefficients represent / represents the point value of the time complexity is \ (O (n ^ 2) \) a.

So we thought, is there a good algorithm to convert time complexity down it?

Of course there

Yes, it is fast Fourier transform!

Pre-knowledge

plural

Order \ (I ^ 2 = -1 \) , the form \ (a + bi \) is a complex number is called, \ (I \) is the imaginary unit.

Complex plane

x-axis represents a real number in the complex plane, y-axis represents the imaginary number.

Each complex \ (a + bi \) one is from the complex plane \ ((0,0) \) point \ ((a, b) \ ) vector.

Die length \ (\ sqrt {A ^ 2 B ^ 2} + \) , the argument is the x-axis positive axis counterclockwise rotated to the angle of the web have an angle.

Followed by adding the parallelogram.

When multiplied, die length multiplied argument added.

Unit Root

Mathematically, n th Root is the power of n is 1 of the complex . They are located on the unit circle in the complex plane, constituting the n-gon vertices, one vertex of which is 1.

These are Baidu Encyclopedia

\ (menci \) Gangster explanation

In the complex plane, with the origin as the center as a circle with a radius, the resulting circle is called the unit circle. The origin as a starting point, the unit circle \ (n \) aliquot of the end point, for n vectors.

The resulting set of positive amplitude and a minimum angle corresponding to a plurality of vectors \ (\ omega_n \) , called \ (n-\) th Root.

(Die length multiplied argument summed) by a complex multiplication of definition, with the (n-1 \) \ vectors respectively corresponding to a plurality of \ (\ omega ^ 2_n, \ omega ^ 3_n ... \ ^ n_n Omega \) , where \ (\ Omega n_n = ^ \ ^ 0_n = Omega. 1 \) .

Euler's formula

\(\large e^{\pi i}=-1,e^{2\pi i}=1\)

Therefore, \ (\ large \ omega_n = e ^ {\ frac {2 \ pi i} n}, \ omega_n ^ k = (e ^ \ frac {2 \ pi i} n) ^ k = \ omega_n ^ k = \ cos \ FRAC {2 \ K} n-PI + I \ SiN \ FRAC {2 \ K} n-PI \) (may be obtained by the vector algorithm)

Properties Unit Root

Erasing Lemma: \ (\ omega_ DN} ^ {} = {DK \ omega_n ^ K, K \ in N, D, n-\ in N ^ + \)

It is clearly established.

Binary Lemma: If n is even, the \ (\ omega_n ^ {k + \ frac n2} = - \ omega_n ^ k \)

Euler equation \ (\ omega_n ^ {k + \ frac n2} = (e ^ \ frac {2 \ pi i} n) ^ {k + \ frac n2} = - (e ^ {\ frac {2 \ pi i} n}) \)

Summing Lemma: \ (\ SUM \ limits_ ^ {J} = {0}. 1-n-(\ omega_n K ^) = J ^ 0, n-, K \ N ^ in +, n-\ the nmid K \)

Proof: \ (\ Large \ SUM \ limits_ ^ {J} = {0}. 1-n-(\ omega_n ^ K) = ^ J \ FRAC {(\ omega_n ^ K). 1-n-^ {} \ ^ - K-omega_n 1} = 0 \)

It is the geometric series summation formula.

Fast Fourier Transform

Consider the polynomial \ (A (x) \) indicates. The \ (n-\) - th root \ (0 \) to the \ (n-1 \) coefficients of a polynomial representation into power, the point value of the resultant vector \ ((A (\ omega_n ^ 0), A (\ omega_n ^ 1), \ ldots, a (\ omega_n ^ {n-1})) \) referred to as its coefficient vector \ ((a_0, a_1, \ ldots, a_ {n-1}) \) discrete Fourier Fourier transform.

Naive Algorithm, time complexity is \ (O (n ^ 2) \)

According to the subject a parity polynomial coefficients divided into two parts:

\(A(x)=(a_0+a_2x^2+a_4x^4+\cdots+a_{n-2}x^{n-2})+(a_1x+a_3x^3+a_5x^5+\cdots+a_{n-1}x^{n-1})\)

Order
\ [\ begin {aligned} A_1 (x) & = a_0 + a_2x + a_4x ^ 2 + \ cdots + a_ {n-2} x ^ {\ frac n2-1} \\ A_2 (x) & = a_1 + a_3x + a_5x ^ 2 + \ cdots
+ a_ {n-1} x ^ {\ frac n2-1} \ end {aligned} \\ \] then
\ [A (x) = A_1 (x ^ 2) + xA_2 ( x ^ 2) \]
Suppose \ (K <\ FRAC N2 \)
\ [A (\ omega_n ^ K) = A1 (\ omega_n ^ {2K}) + \ omega_ n-^ {K} A2 (\ omega_n ^ {2K }) \\ A (\ omega_n ^
k) = A1 (\ omega _ {\ frac n2} ^ k) + \ omega_n ^ kA2 (\ omega _ {\ frac n2} ^ k) \] to \ (\ omega_n ^ {k + \ FRAC N2} \)
\ [A (\ omega_n ^ {K + \ FRAC N2}) = A1 (\ omega_n ^ {2K + n-}) + \ omega_ {n-} ^ {K + \ FRAC N2} A2 (\ omega_ { n} ^ {2k + n}
) \\ = A1 (\ omega _ {\ frac n2} ^ k) - \ omega_n ^ kA2 (\ omega _ {\ frac n2} ^ k) \] Thus, if we know \ (A1 , A2 \) in \ (\ omega _ {\ frac n2} ^ {0 \ text {~} \ frac n2-1} \) all values, we can for all \ (k \ in [0, n ) \) are calculated \ (A \)In \ (\ omega_n ^ {0 \ text ~ n-1} \) All of the values.

So we can go recursive solving, remember high zeros.

Inverse Fourier transform

The point value represented by the polynomial coefficients into said fast Fourier transform can also be used, this process is called an inverse Fourier transform .
Set \ ((y_0, y_1, \ ldots, y_ {n-1}) \) of \ ((a_0, a_1, \ dots, a_ {n-1}) \) is the Fourier transform.

Consider another vector \ ((c_0, c_1, \ dots, c_ {n-1}) \) satisfies
\ [c_k = \ sum \ limits_ {i = 0} ^ {n-1} y_i (\ omega_ {n} ^ {- k}) ^ i
\] expand obtain
\ [c_k = \ sum \ limits_ {i = 0} ^ {k-1} (\ sum \ limits_ {j = 0} ^ {k-1} a_j ( \ omega_ {n} ^ i) ^ j) (\ omega_n ^ {- k}) ^ i \\ c_k = \ sum \ limits_ {i = 0} ^ {k-1} (\ sum \ limits_ {j = 0 } ^ {k-1} a_j (\ omega_ {n} ^ j) ^ i) (\ omega_n ^ {- k}) ^ i \\ c_k = \ sum \ limits_ {i = 0} ^ {k-1} \ sum \ limits_ {j = 0 } ^ {k-1} a_j (\ omega_ {n} ^ {jk}) ^ i \\ c_k = \ sum \ limits_ {i = 0} ^ {k-1} a_j ( \ sum \ limits_ {j = 0
} ^ {k-1} (\ omega_ {n} ^ {jk}) ^ i) \] The summation Lemma, we know that \ (\ sum \ limits_ {j = 0} ^ {k-1} (\ omega_n ^ {jk}) \) when \ (jk \ neq 0 \) when the total is 0, when the \ (j = k \) when \ (n-\) .

\(\therefore c_k=na_k\)

\(\therefore a_k=\frac 1n c_k\)

So, instead of using the unit root of the reciprocal of the unit root, do a similar process fast Fourier transform, and then the results of each divided by \ (the n-\) , is the result of the inverse Fourier transform.

achieve

General use C ++ comes with complex To achieve complex, of course, it can also be hand-written.

Considering the reciprocal of the unit root is equal to its complex conjugate in program implementation, in order to reduce errors, usually std::conj()made "reciprocal unit root" required IDFT.

optimization

Butterfly operations and iteration.

Do not want to talk about here, you can look menci get together blog.

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IL inline
#define RG register
#define gi geti<int>()
#define gl geti<ll>()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
template<typename T>IL bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
template<typename T>IL bool chkmin(T &x,const T &y){return x>y?x=y,1:0;}
template<typename T>
IL T geti()
{
    RG T xi=0;
    RG char ch=gc;
    bool f=0;
    while(!isdigit(ch))ch=='-'?f=1:f,ch=gc;
    while(isdigit(ch))xi=xi*10+ch-48,ch=gc;
    return f?-xi:xi;
}
template<typename T>
IL void pi(T k,char ch=0)
{
    if(k<0)k=-k,putchar('-');
    if(k>=10)pi(k/10);
    putchar(k%10+'0');
    if(ch)putchar(ch);
}
const int N=4e6+7;
typedef double db;
class _complex{
    public:
    db x,y;
    _complex(){}
    _complex(db _x,db _y):x(_x),y(_y){}
};
_complex operator + (const _complex&a,const _complex&b){
    return _complex(a.x+b.x,a.y+b.y);
}
_complex operator - (const _complex&a,const _complex&b){
    return _complex(a.x-b.x,a.y-b.y);
}
_complex operator * (const _complex&a,const _complex&b){
    return _complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
_complex& operator *= (_complex &a,const _complex&b)
{
    return a=a*b;
}
const db PI=acos(-1);
int R[N],L,n,m;
inline void FFT(_complex *a,int opt)
{
    for(int i=0;i<n;++i)if(i<R[i])swap(a[i],a[R[i]]);
    for(int j=1;j<n;j<<=1)
    {
        _complex O(cos(PI/j),sin(PI/j)*opt);
        for(int k=0;k<n;k+=(j<<1)){
            _complex o(1,0);
            for(int l=0;l<j;++l,o*=O)
            {
                _complex Nx=a[k+l],Ny=o*a[j+k+l];
                a[k+l]=Nx+Ny;
                a[j+k+l]=Nx-Ny;
            }
        }
    }
}
_complex f[N],g[N];
int main(void)
{
    n=gi,m=gi;
    for(int i=0;i<=n;++i)f[i].x=gi;
    for(int i=0;i<=m;++i)g[i].x=gi;
    for(m+=n,n=1;n<=m;n<<=1,++L);
    for(int i=0;i<=n;++i)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    FFT(f,1),FFT(g,1);
    for(int i=0;i<=n;++i)f[i]*=g[i];
    FFT(f,-1);
    for(int i=0;i<=m;++i)printf("%d ",(int)(f[i].x/n+0.5));
    return 0;
}

Guess you like

Origin www.cnblogs.com/LLCSBlog/p/11622835.html