forked from amannntank/Competitive-Coding-Library
-
Notifications
You must be signed in to change notification settings - Fork 0
/
FFT_jatin.cpp
111 lines (103 loc) · 3.31 KB
/
FFT_jatin.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Ref - https://www.codechef.com/viewsolution/24509237
typedef long long int ll;
typedef vector<lli> vll;
#define ld double
// polynomial stuff
struct base{
ld x,y;
base(){x=y=0;}
base(ld _x, ld _y){x = _x,y = _y;}
base(ld _x){x = _x, y = 0;}
void operator = (ld _x){x = _x,y = 0;}
ld real(){return x;}
ld imag(){return y;}
base operator + (const base& b){return base(x+b.x,y+b.y);}
void operator += (const base& b){x+=b.x,y+=b.y;}
base operator * (const base& b){return base(x*b.x - y*b.y,x*b.y+y*b.x);}
void operator *= (const base& b){ld p = x*b.x - y*b.y, q = x*b.y+y*b.x; x = p, y = q;}
void operator /= (ld k){x/=k,y/=k;}
base operator - (const base& b){return base(x - b.x,y - b.y);}
void operator -= (const base& b){x -= b.x, y -= b.y;}
base conj(){ return base(x, -y);}
base operator / (ld k) { return base(x / k, y / k);}
void Print(){ cerr << x << " + " << y << "i\n";}
};
double PI = 2.0*acos(0.0);
const int MAXN = 19;
const int maxn = (1<<MAXN);
const int N = 2e5 + 10, mod = 1e9 + 7;
base W[maxn],invW[maxn], P1[maxn], Q1[maxn];
void precompute_powers(){
for(int i = 0;i<maxn/2;i++){
double ang = (2*PI*i)/maxn;
ld _cos = cos(ang), _sin = sin(ang);
W[i] = base(_cos,_sin);
invW[i] = base(_cos,-_sin);
}
}
void fft (vector<base> & a, bool invert) {
int n = (int) a.size();
for (int i=1, j=0; i<n; ++i) {
int bit = n >> 1;
for (; j>=bit; bit>>=1)
j -= bit;
j += bit;
if (i < j)
swap (a[i], a[j]);
}
for (int len=2; len<=n; len<<=1) {
for (int i=0; i<n; i+=len) {
int ind = 0,add = maxn/len;
for (int j=0; j<len/2; ++j) {
base u = a[i+j], v = (a[i+j+len/2] * (invert?invW[ind]:W[ind]));
a[i+j] = (u + v);
a[i+j+len/2] = (u - v);
ind += add;
}
}
}
if (invert) for (int i=0; i<n; ++i) a[i] /= n;
}
// 4 FFTs in total for a precise convolution
void mul_big_mod(vll &a, vll & b){
int n1 = a.size(),n2 = b.size();
int final_size = a.size() + b.size() - 1;
int n = 1;
while(n < final_size) n <<= 1;
vector<base> P(n), Q(n);
const int SQRTMOD = (int)sqrt(mod) + 10;
for(int i = 0;i < n1;i++) P[i] = base(a[i] % SQRTMOD, a[i] / SQRTMOD);
for(int i = 0;i < n2;i++) Q[i] = base(b[i] % SQRTMOD, b[i] / SQRTMOD);
fft(P, 0);
fft(Q, 0);
base A1, A2, B1, B2, X, Y;
for(int i = 0; i < n; i++){
X = P[i];
Y = P[(n - i) % n].conj();
A1 = (X + Y) * base(0.5, 0);
A2 = (X - Y) * base(0, -0.5);
X = Q[i];
Y = Q[(n - i) % n].conj();
B1 = (X + Y) * base(0.5, 0);
B2 = (X - Y) * base(0, -0.5);
P1[i] = A1 * B1 + A2 * B2 * base(0, 1);
Q1[i] = A1 * B2 + A2 * B1;
}
for(int i = 0; i < n; i++) P[i] = P1[i], Q[i] = Q1[i];
fft(P, 1);
fft(Q, 1);
a.resize(final_size);
for(int i = 0; i < final_size; i++){
ll x = (ll)(P[i].real() + 0.5);
ll y = (ll)(P[i].imag() + 0.5) % mod;
ll z = (ll)(Q[i].real() + 0.5);
a[i] = (x + ((y * SQRTMOD + z) % mod) * SQRTMOD) % mod;
}
}
// Ensure all terms are positive.
vll mul(vll a, vll b){
mul_big_mod(a, b);
return a;
}
// Call this in main.
precompute_powers();