polynomial multiplication
given adegree polynomial
and
degree polynomial
, find out
with
of convolution.
Input format
Two integers in the first line。
next linenumbers, expressed from low to high
coefficient.
next linenumbers, expressed from low to high
coefficient.
Output format
one linenumbers, expressed from low to high
coefficient.
Input and output samples
Input sample
1 2
1 2
1 2 1
Output sample
1 4 5 2
Problem analysis
Suppose two polynomialsand
, the two polynomials can be written as:
The traditional method is to use the coefficients of two polynomials to perform a convolution operation to obtain adegree polynomial
:
The time complexity of this convolution operation is, obviously it is unbearable when the data range is large, and usingFast Fourier TransformThe time complexity can be reduced to
。
Introduction to FFT
Fast Fourier transform (fast Fourier transform) is the collective name for efficient and fast calculation methods that use computers to calculate discrete Fourier transforms (DFT), referred to as FFT. Fast Fourier transform was proposed by J.W. Cooley and T.W. Tukey in 1965. Using this algorithm can greatly reduce the number of multiplications required by the computer to calculate the discrete Fourier transform. In particular, the more sampling points N are transformed, the more significant the calculation savings of the FFT algorithm will be.
FFT (Fast Fourier Transformation) is a fast algorithm for Discrete Fourier Transform (DFT). That is the fast Fourier transform. It is obtained by improving the discrete Fourier transform algorithm based on the odd, even, imaginary, real and other characteristics of the discrete Fourier transform.
——Baidu Encyclopedia
The problem to be solved is the multiplication of polynomials, and the representation method of a polynomial is not unique. Traditionally, the representation of polynomials uses the coefficient representation method, that is, for a polynomialcan be determined by a coefficient vector
The only representation.
In addition to coefficient representation, polynomials can also be represented by point values. For polynomials, selected
a
value
Bringing in polynomials for calculation, we get
pip value) this
Point values can also uniquely represent polynomials
。
So when we use the same vectorAfter obtaining the point value representations of two polynomials, multiply them by the corresponding point values to get
That is, the point value representation of the product polynomial of two polynomials. The time complexity of this process is
。
One thing to note is that when the degree of two polynomials isWhen , the degree of their product polynomial is
, so when calculating using point value representation, you should choose to use the point value representation when calculating the point value representation of two polynomials
variables, so that the result obtained uniquely represents the product polynomial
。
However, for a polynomialFor example, substituting any selected variable
The time complexity of calculating its point value representation is still
, and does not have an optimization effect, but the fast Fourier transform solves this problem, reducing the time complexity of converting the coefficient representation into a point value representation as
。
Fast Fourier Transform FFT
FFT is selected when converting the coefficient representation of the calculation polynomial into the point value representation.complex planeon the unit circleunit complex rootCalculate the point value of a polynomial as a variable, here the unit root
Satisfy some of the following properties (if you don’t understand anything, you can look up some relevant knowledge about complex numbers by yourself):

Figure 1 FFT
All of the above properties can be derived fromEuler formulaObtained, the derivation process is not the focus of FFT and is omitted here.
For a polynomial, we can divide it to separate even-order terms from odd-order terms, assuming here
is an odd number, we get:
We define two polynomials respectively:
Then the original polynomialIt can be expressed as:
willSubstitute into the above equation:
willSubstitute into the above equation:
From this it can be found thatand
Only one symbol is different during the calculation, so when performing enumeration calculations
can be obtained directly
value, using this method to divide and conquer can reduce the complexity to
。
Inverse Fourier Transform IFFT
Using the above method, the point value representation of the product polynomial is obtained, so the problem that needs to be solved now is how to convert the point value representation back to the coefficient representation.
Assume that the FFT point value of the polynomial is expressed as, its coefficient is expressed as
, according to the FFT principle,
It can be expressed as follows:
takeofconjugate complex numbers
, define the vector as follows
:
Then the following formula can be derived from the definition:

Figure 2 FFT
For unit roots in the complex plane, has the following properties:
So we can get:
Therefore, after using FFT to obtain the point value representation of the polynomial, you only need to replace the variable with the conjugate complex number of the originally selected unit root and perform another FFT to obtain the coefficient representation of the polynomial.
There is an issue that needs to be explained here. Our above discussions are all based on**for
to the power ofunder the conditions, then when
No
Required when the power ofwill
expand to be greater than
the smallest
**, when performing the inverse Fourier transform, we can find through the above derivation that when we calculate
in
The value is greater than the original
, does not exist
situation, so we obtain
for
, representing the polynomial
The coefficient of the secondary term is
。
But the problem doesn't end here
When the range of some cancer data is very large, when using recursion for calculation, a large amount of recursion will cause stack overflow. Is there any way to avoid recursion?
Iterative implementation of FFT
For such a sequence, we observe the process of dividing it into two parts:

Figure 3 FFT iteration
We discovered a magical property. After bisecting this sequence, the binary of the sequence can be obtained by flipping the binary of the original sequence. Then we can take advantage of this property and use aThe method can directly obtain the final sequence, thus eliminating the recursive process, and can be implemented by reverse recursion using the final sequence.
Rader algorithm
Rader algorithmThat is an algorithm to implement the above operation, fornumber, we take increasing natural numbers
It is called a sequential sequence; for each number in the sequential sequence, convert its binary in reverse order and then convert it into decimal, which is called a reverse sequence.
For a sequential sequence, theThe binary number can be regarded as the
(Here is integer divisibility) The binary number of the number is shifted one bit to the left, and then according to
The parity of
Or don’t add
。
Then to get its inverse sequence, you only need to reverse this operation, that is, theThe binary number can be regarded as the
The binary number of the number is shifted one bit to the right, and then according to
The parity of
Or don’t add
, where the highest position is the
Bit.
Iteratively perform FFT (Butterfly Transform)
The recursive sequence is obtained using Rader algorithm, so how to get the final answer through iteration?
This is actually similar to the idea of iteratively implementing the 01 backpack.in
When the point value of each power of the unit root is
The powers of subunit roots are
or
The point value at has been calculated and stored in
array, then use it directly in the iteration process of the next layer
The answer stored in the array can continue to be iteratively calculated.
Iterative optimization of FFT code implementation
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath> using namespace std; const int N = 300010;
const double PI = acos(-1); int n, m;
struct Complex
{ double x, y; Complex operator+ (const Complex& t) const { return {x + t.x, y + t.y}; } Complex operator- (const Complex& t) const { return {x - t.x, y - t.y}; } Complex operator* (const Complex& t) const { return {x * t.x - y * t.y, x * t.y + y * t.x}; }
}a[N], b[N];
int rev[N], bit, tot; void fft(Complex a[], int inv)
{ for (int i = 0; i < tot; i ++ ) if (i < rev[i]) swap(a[i], a[rev[i]]); for (int mid = 1; mid < tot; mid <<= 1) { auto w1 = Complex({cos(PI / mid), inv * sin(PI / mid)}); for (int i = 0; i < tot; i += mid * 2) { auto wk = Complex({1, 0}); for (int j = 0; j < mid; j ++, wk = wk * w1) { auto x = a[i + j], y = wk * a[i + j + mid]; a[i + j] = x + y, a[i + j + mid] = x - y; } } }
} int main()
{ scanf("%d%d", &n, &m); for (int i = 0; i <= n; i ++ ) scanf("%lf", &a[i].x); for (int i = 0; i <= m; i ++ ) scanf("%lf", &b[i].x); while ((1 << bit) < n + m + 1) bit ++; tot = 1 << bit; for (int i = 0; i < tot; i ++ ) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1)); fft(a, 1), fft(b, 1); for (int i = 0; i < tot; i ++ ) a[i] = a[i] * b[i]; fft(a, -1); for (int i = 0; i <= n + m; i ++ ) printf("%d ", (int)(a[i].x / tot + 0.5)); return 0;
}