1
1
/**
2
- * Author: chilli
2
+ * Author: chilli, Andrew He, Adamant
3
3
* Date: 2019-04-27
4
4
* Description: A FFT based Polynomial class.
5
5
*/
8
8
#include "../number-theory/ModularArithmetic.h"
9
9
#include "FastFourierTransform.h"
10
10
#include "FastFourierTransformMod.h"
11
+ // #include "NumberTheoreticTransform.h"
11
12
12
13
typedef Mod num ;
13
14
typedef vector < num > poly ;
14
15
vector < Mod > conv (vector < Mod > a , vector < Mod > b ) {
15
- // auto res = convMod<mod>(vl(all(a)), vl(all(b)));
16
- auto res = conv (vl (all (a )), vl (all (b )));
16
+ auto res = convMod < mod > (vl (all (a )), vl (all (b )));
17
+ // auto res = conv(vl(all(a)), vl(all(b)));
17
18
return vector < Mod > (all (res ));
18
19
}
19
20
poly & operator += (poly & a , const poly & b ) {
@@ -39,12 +40,25 @@ poly operator*(poly a, const num b) {
39
40
}
40
41
OP (* , *=) OP (+ , += ) OP (- , -= );
41
42
poly modK (poly a , int k ) { return {a .begin (), a .begin () + min (k , sz (a ))}; }
43
+ // Currently there's two of them - the second is the original one (simply following the formula), the first one is a version Adamant says is faster.
44
+ // I haven't been able to replicate the difference in performance, however.
42
45
poly inverse (poly A ) {
43
46
poly B = poly ({num (1 ) / A [0 ]});
44
- while (sz (B ) < sz (A ))
45
- B = modK (B * (poly ({num (2 )}) - A * B ), 2 * sz (B ));
47
+ while (sz (B ) < sz (A )){
48
+ poly C = B * modK (A , 2 * sz (B ));
49
+ C = poly (C .begin ()+ sz (B ), C .end ());
50
+ C = modK (B * C , sz (B ));
51
+ C .insert (C .begin (), sz (B ), 0 );
52
+ B - = C ;
53
+ }
46
54
return modK (B , sz (A ));
47
55
}
56
+ // poly inverse(poly A) {
57
+ // poly B = poly({num(1) / A[0]});
58
+ // while (sz(B) < sz(A))
59
+ // B = modK(B * (poly({num(2)}) - modK(A, 2*sz(B)) * B), 2 * sz(B));
60
+ // return modK(B, sz(A));
61
+ // }
48
62
poly & operator /= (poly & a , poly b ) {
49
63
if (sz (a ) < sz (b ))
50
64
return a = {};
@@ -73,10 +87,11 @@ poly deriv(poly a) {
73
87
return b ;
74
88
}
75
89
poly integr (poly a ) {
76
- if (a .empty ())
77
- return {0 };
90
+ if (a .empty ()) return {0 };
78
91
poly b (sz (a ) + 1 );
79
- rep (i , 1 , sz (b )) b [i ] = a [i - 1 ] / num (i );
92
+ b [1 ] = num (1 );
93
+ rep (i , 2 , sz (b )) b [i ] = b [mod %i ]* Mod (- mod /i + mod );
94
+ rep (i , 1 ,sz (b )) b [i ] = a [i - 1 ] * b [i ];
80
95
return b ;
81
96
}
82
97
poly log (poly a ) { return modK (integr (deriv (a ) * inverse (a )), sz (a )); }
@@ -102,4 +117,33 @@ poly pow(poly a, ll m) {
102
117
auto res = exp (log (a ) * num (m )) * (j ^ m );
103
118
res .insert (res .begin (), p * m , 0 );
104
119
return modK (res , n );
120
+ }
121
+
122
+ vector < num > eval (const poly & a , const vector < num > & x ) {
123
+ int n = sz (x );
124
+ if (!n ) return {};
125
+ vector < poly > up (2 * n );
126
+ rep (i , 0 , n ) up [i + n ] = poly ({num (0 ) - x [i ], 1 });
127
+ for (int i = n - 1 ; i > 0 ; i -- )
128
+ up [i ] = up [2 * i ] * up [2 * i + 1 ];
129
+ vector < poly > down (2 * n );
130
+ down [1 ] = a % up [1 ];
131
+ rep (i , 2 , 2 * n ) down [i ] = down [i / 2 ] % up [i ];
132
+ vector < num > y (n );
133
+ rep (i , 0 , n ) y [i ] = down [i + n ][0 ];
134
+ return y ;
135
+ }
136
+
137
+ poly interp (vector < num > x , vector < num > y ) {
138
+ int n = sz (x );
139
+ vector < poly > up (n * 2 );
140
+ rep (i , 0 , n ) up [i + n ] = poly ({num (0 ) - x [i ], num (1 )});
141
+ for (int i = n - 1 ; i > 0 ; i -- )
142
+ up [i ] = up [2 * i ] * up [2 * i + 1 ];
143
+ vector < num > a = eval (deriv (up [1 ]), x );
144
+ vector < poly > down (2 * n );
145
+ rep (i , 0 , n ) down [i + n ] = poly ({y [i ] * (num (1 ) / a [i ])});
146
+ for (int i = n - 1 ; i > 0 ; i -- )
147
+ down [i ] = down [i * 2 ] * up [i * 2 + 1 ] + down [i * 2 + 1 ] * up [i * 2 ];
148
+ return down [1 ];
105
149
}
0 commit comments