/**
This program used to to multiply two polynomials A and B have the same (M/2-1)-degree ( M is power of 2 )
@result C is a polynomial with M-1 degree ( M is power of 2 )
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <complex>
using namespace std;
const long double PI = acos ( - 1 ) ;
const int M = ( 1 << 3 ) ;
typedef long double ld;
complex< ld> getPrimitiveRootOfUnity( int gen) {
return complex< ld> ( cos ( 2 * PI/ gen) , sin ( 2 * PI/ gen) ) ;
}
class Polynomial {
private :
int sz;
public :
complex< ld> * f;
Polynomial( int sz) {
this- > sz = sz;
this- > f = new complex< ld> [ this- > sz] ;
for ( int i = 0 ; i < this- > sz; i++ ) this- > f[ i] = complex< ld> ( 0 ,0 ) ;
}
} ;
inline Polynomial FFT( Polynomial A, int m, complex< ld> w)
{
if ( m== 1 ) return A;
Polynomial A_even( m/ 2 ) ;
Polynomial A_odd( m/ 2 ) ;
for ( int i = 0 ; i < m; i+ = 2 ) {
A_even.f [ i/ 2 ] = A.f [ i] ;
A_odd.f [ i/ 2 ] = A.f [ i+ 1 ] ;
}
Polynomial F_even = FFT( A_even, m/ 2 , w* w) ; //w^2 is a primitive m/2-th root of unity
Polynomial F_odd = FFT( A_odd, m/ 2 , w* w) ;
Polynomial F( m) ;
complex< ld> x( 1 ,0 ) ;
for ( int j= 0 ; j < m/ 2 ; ++ j) {
F.f [ j] = F_even.f [ j] + x* F_odd.f [ j] ;
F.f [ j+ m/ 2 ] = F_even.f [ j] - x* F_odd.f [ j] ;
x = x * w;
}
return F;
}
int main( ) {
Polynomial A( M/ 2 ) , B( M/ 2 ) ;
// enter polynomial A and B both with M/2 degree
enterPolynomial_A;
enterPolynomial_B;
complex< ld> w = getPrimitiveRootOfUnity( M) ;
Polynomial F_A = FFT( A, M, w) ;
Polynomial F_B = FFT( B, M, w) ;
Polynomial F_C( M) ;
for ( int i = 0 ; i < M; i++ ) F_C.f [ i] = F_A.f [ i] * F_B.f [ i] ;
// w_ = w^{-1}
complex< ld> w_( 1 ,0 ) ;
for ( int i = 0 ; i < M- 1 ; i++ ) w_ * = w;
// 2 last statement to compute result polynomial, result going to be located in C
Polynomial C = FFT( F_C, M, w_) ;
for ( int i = 0 ; i < M; i++ ) C.f [ i] * = ( ld) 1.0 / M;
return 0 ;
}
LyoqCiAgICBUaGlzIHByb2dyYW0gdXNlZCB0byB0byBtdWx0aXBseSB0d28gcG9seW5vbWlhbHMgQSBhbmQgQiBoYXZlIHRoZSBzYW1lIChNLzItMSktZGVncmVlICggTSBpcyBwb3dlciBvZiAyICkKICAgIEByZXN1bHQgQyBpcyBhIHBvbHlub21pYWwgd2l0aCBNLTEgZGVncmVlICggTSBpcyBwb3dlciBvZiAyICkKKi8KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y3N0ZGlvPgojaW5jbHVkZSA8Y21hdGg+CiNpbmNsdWRlIDxjb21wbGV4Pgp1c2luZyBuYW1lc3BhY2Ugc3RkOwpjb25zdCBsb25nIGRvdWJsZSBQSSA9IGFjb3MoLTEpOwpjb25zdCBpbnQgTSA9ICgxPDwzKTsKdHlwZWRlZiBsb25nIGRvdWJsZSBsZDsKCmNvbXBsZXg8bGQ+IGdldFByaW1pdGl2ZVJvb3RPZlVuaXR5KGludCBnZW4pIHsKICAgIHJldHVybiBjb21wbGV4PGxkPihjb3MoMipQSS9nZW4pLCBzaW4oMipQSS9nZW4pKTsKfQpjbGFzcyBQb2x5bm9taWFsIHsKcHJpdmF0ZToKICAgIGludCBzejsKcHVibGljOgogICAgY29tcGxleDxsZD4gKmY7CiAgICBQb2x5bm9taWFsKGludCBzeikgewogICAgICAgIHRoaXMtPnN6ID0gc3o7CiAgICAgICAgdGhpcy0+ZiA9IG5ldyBjb21wbGV4PGxkPlt0aGlzLT5zel07CiAgICAgICAgZm9yKGludCBpID0gMDsgaSA8IHRoaXMtPnN6OyBpKyspIHRoaXMtPmZbaV0gPSBjb21wbGV4PGxkPigwLDApOwogICAgfQp9OwppbmxpbmUgUG9seW5vbWlhbCBGRlQoUG9seW5vbWlhbCBBLCBpbnQgbSwgY29tcGxleDxsZD4gdykKewogICAgaWYgKG09PTEpIHJldHVybiBBOwoKICAgIFBvbHlub21pYWwgQV9ldmVuKG0vMik7CiAgICBQb2x5bm9taWFsIEFfb2RkKG0vMik7CiAgICBmb3IoaW50IGkgPSAwOyBpIDwgbTsgaSs9MikgewogICAgICAgIEFfZXZlbi5mW2kvMl0gPSBBLmZbaV07CiAgICAgICAgQV9vZGQuZltpLzJdID0gQS5mW2krMV07CiAgICB9CiAgICBQb2x5bm9taWFsIEZfZXZlbiA9IEZGVChBX2V2ZW4sIG0vMiwgdyp3KTsgICAgLy93XjIgaXMgYSBwcmltaXRpdmUgbS8yLXRoIHJvb3Qgb2YgdW5pdHkKICAgIFBvbHlub21pYWwgRl9vZGQgPSBGRlQoQV9vZGQsIG0vMiwgdyp3KTsKICAgIFBvbHlub21pYWwgRihtKTsKICAgIGNvbXBsZXg8bGQ+IHgoMSwwKTsKICAgIGZvciAoaW50IGo9MDsgaiA8IG0vMjsgKytqKSB7CiAgICAgIEYuZltqXSA9IEZfZXZlbi5mW2pdICsgeCpGX29kZC5mW2pdOwogICAgICBGLmZbaittLzJdID0gRl9ldmVuLmZbal0gLSB4KkZfb2RkLmZbal07CiAgICAgIHggPSB4ICogdzsKICAgIH0KICAgIHJldHVybiBGOwp9CmludCBtYWluKCkgewogICAgUG9seW5vbWlhbCBBKE0vMiksIEIoTS8yKTsKICAgIC8vIGVudGVyIHBvbHlub21pYWwgQSBhbmQgQiBib3RoIHdpdGggTS8yIGRlZ3JlZQogICAgZW50ZXJQb2x5bm9taWFsX0E7CiAgICBlbnRlclBvbHlub21pYWxfQjsKICAgIGNvbXBsZXg8bGQ+IHcgPSBnZXRQcmltaXRpdmVSb290T2ZVbml0eShNKTsKICAgIFBvbHlub21pYWwgRl9BID0gRkZUKEEsIE0sIHcpOwogICAgUG9seW5vbWlhbCBGX0IgPSBGRlQoQiwgTSwgdyk7CiAgICBQb2x5bm9taWFsIEZfQyhNKTsKICAgIGZvcihpbnQgaSA9IDA7IGkgPCBNOyBpKyspIEZfQy5mW2ldID0gRl9BLmZbaV0gKiBGX0IuZltpXTsKICAgIC8vIHdfID0gd157LTF9CiAgICBjb21wbGV4PGxkPiB3XygxLDApOwogICAgZm9yKGludCBpID0gMDsgaSA8IE0tMTsgaSsrKSB3XyAqPSB3OwogICAgLy8gMiBsYXN0IHN0YXRlbWVudCB0byBjb21wdXRlIHJlc3VsdCBwb2x5bm9taWFsLCByZXN1bHQgZ29pbmcgdG8gYmUgbG9jYXRlZCBpbiBDCiAgICBQb2x5bm9taWFsIEMgPSBGRlQoRl9DLCBNLCB3Xyk7CiAgICBmb3IoaW50IGkgPSAwOyBpIDwgTTsgaSsrKSBDLmZbaV0gKj0gKGxkKTEuMC9NOwoJcmV0dXJuIDA7Cn0K