1 做多项式题就像嗑药,出多项式题就像贩毒。 ——某著名 OIer
代码戳这里
例题戳这里
多项式乘法
快速傅里叶变换 (FFT)
直接上链接(
快速傅里叶变换(FFT)详解 - 自为风月马前卒
总的来说就是先 DFT 从系数表示法到点值表示法,再 IDFT 从点值表示法到系数表示法。
简单说一下不太理解的,在 DFT 中 ω n k = − ω n k + n 2 \omega_n^k = -\omega_n^{k+\frac{n}{2}} ω n k = − ω n k + 2 n ,其实就是在单位圆上旋转了 180 ° 180° 1 8 0 ° 。
感性理解 DFT 和 IDFT 是逆运算,所以 ω n \omega_n ω n 就是相反数。
Code
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 #include <bits/stdc++.h> #define ll long long #define db double #define gc getchar #define pc putchar using namespace std;namespace IO{ template <typename T> void read (T &x) { x = 0 ; bool f = 0 ; char c = gc (); while (!isdigit (c)) f |= c == '-' , c = gc (); while (isdigit (c)) x = x * 10 + c - '0' , c = gc (); if (f) x = -x; } template <typename T> void write (T x) { if (x < 0 ) pc ('-' ), x = -x; if (x > 9 ) write (x / 10 ); pc ('0' + x % 10 ); } } using namespace IO;struct Complex { db x, y; Complex (db _x = 0.0 , db _y = 0.0 ) { x = _x, y = _y; } Complex operator + (const Complex b) const { return Complex (x + b.x, y + b.y); } Complex operator - (const Complex b) const { return Complex (x - b.x, y - b.y); } Complex operator * (const Complex b) const { return Complex (x * b.x - y * b.y, x * b.y + y * b.x); } }; const int N = 1e6 + 5 ;const db pi = acos (-1.0 );int n, m;Complex f[N << 2 ], g[N << 2 ]; int len = 1 , bit, rev[N << 2 ];void FFT (Complex a[], int type) { for (int i = 0 ; i < len; i++) if (i < rev[i]) swap (a[i], a[rev[i]]); for (int mid = 1 ; mid < len; mid <<= 1 ) { Complex wn (cos(pi / mid), type * sin(pi / mid)) ; for (int i = 0 ; i < len; i += (mid << 1 )) { Complex w (1 , 0 ) ; for (int j = 0 ; j < mid; j++, w = w * wn) { Complex x = a[i + j], y = w * a[i + mid + j]; a[i + j] = x + y; a[i + mid + j] = x - y; } } } if (type == -1 ) for (int i = 0 ; i < len; i++) a[i].x /= len; return ; } int main () { read (n), read (m); for (int i = 0 ; i <= n; i++) read (f[i].x); for (int i = 0 ; i <= m; i++) read (g[i].x); while (len <= n + m) len <<= 1 , bit++; for (int i = 0 ; i < len; i++) rev[i] = (rev[i >> 1 ] >> 1 ) | ((i & 1 ) << (bit - 1 )); FFT (f, 1 ); FFT (g, 1 ); for (int i = 0 ; i < len; i++) f[i] = f[i] * g[i]; FFT (f, -1 ); for (int i = 0 ; i <= n + m; i++) printf ("%lld " , (ll)(f[i].x + 0.5 )); pc ('\n' ); return 0 ; }
快速数论变换 (NTT)
继续上链接(
快速数论变换(NTT)小结 - 自为风月马前卒
就是把 FFT 中的 ω n \omega_n ω n 改为了 g p − 1 n g^{\frac{p-1}{n}} g n p − 1 ,其中 g g g 为模数的原根。
ω n ≡ g p − 1 n ( m o d p ) \omega_n \equiv g^{\frac{p-1}{n}}\ (\bmod\ p)
ω n ≡ g n p − 1 ( m o d p )
证明就算了
然后在 IDFT 时就感性理解地取一下逆元就行了(
Code
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 #include <bits/stdc++.h> #define ll long long #define db double #define gc getchar #define pc putchar #define swap(a, b) a ^= b ^= a ^= b using namespace std;namespace IO{ template <typename T> void read (T &x) { x = 0 ; bool f = 0 ; char c = gc (); while (!isdigit (c)) f |= c == '-' , c = gc (); while (isdigit (c)) x = x * 10 + c - '0' , c = gc (); if (f) x = -x; } template <typename T> void write (T x) { if (x < 0 ) pc ('-' ), x = -x; if (x > 9 ) write (x / 10 ); pc ('0' + x % 10 ); } } using namespace IO;const int N = 1e6 + 5 ;const int p = 998244353 ;const int G = 3 ;const int Gi = 332748118 ;int n, m, len = 1 , bit;ll f[N << 2 ], g[N << 2 ]; int rev[N << 2 ];ll qpow (ll a, int b) { ll res = 1 ; while (b) { if (b & 1 ) res = res * a % p; a = a * a % p, b >>= 1 ; } return res % p; } void NTT (ll a[], int type) { for (int i = 0 ; i < len; i++) if (i < rev[i]) swap (a[i], a[rev[i]]); for (int mid = 1 ; mid < len; mid <<= 1 ) { ll wn = qpow (type == 1 ? G : Gi, (p - 1 ) / (mid << 1 )); for (int i = 0 ; i < len; i += (mid << 1 )) { ll w = 1 ; for (int j = 0 ; j < mid; j++, w = w * wn % p) { ll x = a[i + j], y = w * a[i + mid + j] % p; a[i + j] = (x + y) % p; a[i + mid + j] = (x - y + p) % p; } } } ll inv = qpow (len, p - 2 ); if (type == -1 ) for (int i = 0 ; i < len; i++) f[i] = f[i] * inv % p; return ; } int main () { read (n), read (m); for (int i = 0 ; i <= n; i++) read (f[i]); for (int i = 0 ; i <= m; i++) read (g[i]); while (len <= n + m) len <<= 1 , bit++; for (int i = 0 ; i < len; i++) rev[i] = (rev[i >> 1 ] >> 1 ) | ((i & 1 ) << (bit - 1 )); NTT (f, 1 ); NTT (g, 1 ); for (int i = 0 ; i < len; i++) f[i] = f[i] * g[i] % p; NTT (f, -1 ); for (int i = 0 ; i <= n + m; i++) write (f[i]), pc (' ' ); pc ('\n' ); return 0 ; }
多项式求逆
对于一个多项式 F ( x ) F(x) F ( x ) 求 一个多项式 G ( x ) G(x) G ( x ) ,满足 F ( x ) ∗ G ( x ) ≡ 1 ( m o d x n ) F(x)*G(x)\equiv 1\ (\bmod\ x^n) F ( x ) ∗ G ( x ) ≡ 1 ( m o d x n ) ,系数对 998244353 998244353 9 9 8 2 4 4 3 5 3 取模。
就是多项式的逆元。
推一下式子
设
A ( x ) ∗ B ( x ) ≡ 1 ( m o d x n ) A ( x ) ∗ C ( x ) ≡ 1 ( m o d x n 2 ) A(x)*B(x) \equiv 1\quad (\bmod\ x^n)\\
A(x)*C(x)\equiv 1\quad (\bmod\ x^{\frac{n}{2}})
A ( x ) ∗ B ( x ) ≡ 1 ( m o d x n ) A ( x ) ∗ C ( x ) ≡ 1 ( m o d x 2 n )
那么
A ( x ) ∗ ( B ( x ) − C ( x ) ) ≡ 0 ( m o d x n 2 ) B ( x ) − C ( x ) ≡ 0 ( m o d x n 2 ) A(x)*(B(x)-C(x))\equiv 0\quad (\bmod\ x^{\frac{n}{2}}) \\
B(x)-C(x)\equiv 0\quad (\bmod\ x^{\frac{n}{2}})
A ( x ) ∗ ( B ( x ) − C ( x ) ) ≡ 0 ( m o d x 2 n ) B ( x ) − C ( x ) ≡ 0 ( m o d x 2 n )
我们要把模数改为 x n x^n x n ,只需要平方一下
[ B ( x ) − C ( x ) ] 2 ≡ 0 ( m o d x n ) B 2 ( x ) − 2 B ( x ) ∗ C ( x ) + C 2 ( x ) ≡ 0 ( m o d x n ) [B(x)-C(x)]^2\equiv 0\quad (\bmod\ x^n) \\
B^2(x)-2B(x)*C(x)+C^2(x)\equiv 0\quad (\bmod\ x^n)\\
[ B ( x ) − C ( x ) ] 2 ≡ 0 ( m o d x n ) B 2 ( x ) − 2 B ( x ) ∗ C ( x ) + C 2 ( x ) ≡ 0 ( m o d x n )
将等式左边乘上 A ( x ) A(x) A ( x ) 不影响等号
因为
A ( x ) ∗ B ( x ) ≡ 1 ( m o d x n ) A(x)*B(x)\equiv 1\ (\bmod\ x^n)
A ( x ) ∗ B ( x ) ≡ 1 ( m o d x n )
所以可以将 A ( x ) ∗ B ( x ) A(x)*B(x) A ( x ) ∗ B ( x ) 都去掉
B ( x ) − 2 C ( x ) + A ( x ) ∗ C 2 ( x ) ≡ 0 ( m o d x n ) B ( x ) ≡ 2 C ( x ) − A ( x ) ∗ C 2 ( x ) ( m o d x n ) B(x)-2C(x)+A(x)*C^2(x)\equiv 0\quad (\bmod\ x^n) \\
B(x)\equiv 2C(x)-A(x)*C^2(x)\quad (\bmod\ x^n)
B ( x ) − 2 C ( x ) + A ( x ) ∗ C 2 ( x ) ≡ 0 ( m o d x n ) B ( x ) ≡ 2 C ( x ) − A ( x ) ∗ C 2 ( x ) ( m o d x n )
我们只需要求出 C ( x ) C(x) C ( x ) ,而 C ( x ) C(x) C ( x ) 与 B ( x ) B(x) B ( x ) 的形式是一样的,只是模数不一样,所以可以递归求解,当然也可以递推。
多项式 ln
给定一个多项式 A ( x ) A(x) A ( x ) ,求一个多项式 B ( x ) B(x) B ( x ) ,满足 B ( x ) ≡ ln A ( x ) ( m o d x n ) B(x)\equiv \ln A(x)\quad (\bmod\ x^n) B ( x ) ≡ ln A ( x ) ( m o d x n ) 。
设 f ( x ) = ln x f(x) = \ln x f ( x ) = ln x
ln \ln ln 不好处理,但是对 ln \ln ln 求导后就很好算了,f ′ ( x ) = 1 x f'(x)=\dfrac{1}{x} f ′ ( x ) = x 1
所以将同余号两边同时求导,B ′ ( x ) ≡ f ′ ( A ( x ) ) ∗ A ′ ( x ) B'(x)\equiv f'(A(x))*A'(x) B ′ ( x ) ≡ f ′ ( A ( x ) ) ∗ A ′ ( x ) (复合函数求导)
因为 f ′ ( A ( x ) ) = 1 A ( x ) f'(A(x))=\dfrac{1}{A(x)} f ′ ( A ( x ) ) = A ( x ) 1
所以 B ′ ( x ) ≡ A ′ ( x ) A ( x ) B'(x)\equiv \dfrac{A'(x)}{A(x)} B ′ ( x ) ≡ A ( x ) A ′ ( x )
有了 B ′ ( x ) B'(x) B ′ ( x ) 后再积分求出 B ( x ) B(x) B ( x )
求导公式:( x a ) ′ = a x a − 1 (x^a)'=ax^{a-1} ( x a ) ′ = a x a − 1
积分公式:∫ x a d x = 1 a + 1 x a + 1 \int x^adx=\dfrac{1}{a+1}x^{a+1} ∫ x a d x = a + 1 1 x a + 1
积分就是求导的逆运算,你会发现把 1 a + 1 x a + 1 \dfrac{1}{a+1}x^{a+1} a + 1 1 x a + 1 求导后就是 x a x^a x a 。
多项式开根
给定一个多项式 A ( x ) A(x) A ( x ) ,求一个多项式 B ( x ) B(x) B ( x ) ,满足 B 2 ( x ) ≡ A ( x ) ( m o d x n ) B^2(x)\equiv A(x)\quad(\bmod\ x^n) B 2 ( x ) ≡ A ( x ) ( m o d x n ) 。
设
B 0 2 ( x ) ≡ A ( x ) ( m o d x n 2 ) B_0^2(x)\equiv A(x)\quad (\bmod\ x^{\frac{n}{2}}) \\
B 0 2 ( x ) ≡ A ( x ) ( m o d x 2 n )
那么
B 2 ( x ) ≡ B 0 2 ( x ) ( m o d x n 2 ) B ( x ) ≡ B 0 ( x ) ( m o d x n 2 ) B ( x ) − B 0 ( x ) ≡ 0 ( m o d x n 2 ) ( B ( x ) − B 0 ( x ) ) 2 ≡ 0 ( m o d x n ) B 2 ( x ) − 2 B ( x ) B 0 ( x ) + B 0 2 ( x ) ≡ 0 ( m o d x n ) A ( x ) − 2 B ( x ) B 0 ( x ) + B 0 2 ( x ) ≡ 0 ( m o d x n ) B ( x ) ≡ A ( x ) + B 0 2 ( x ) 2 B 0 ( x ) ( m o d x n ) B ( x ) ≡ 1 2 [ A ( x ) B 0 ( x ) + B 0 ( x ) ] ( m o d x n ) B^2(x)\equiv B_0^2(x)\quad(\bmod\ x^{\frac{n}{2}}) \\
B(x)\equiv B_0(x)\quad (\bmod\ x^{\frac{n}{2}}) \\
B(x)-B_0(x)\equiv 0\quad (\bmod\ x^{\frac{n}{2}}) \\
(B(x)-B_0(x))^2\equiv 0\quad (\bmod\ x^n) \\
B^2(x)-2B(x)B_0(x)+B_0^2(x)\equiv 0\quad (\bmod\ x^n) \\
A(x)-2B(x)B_0(x)+B_0^2(x)\equiv 0\quad (\bmod\ x^n) \\
B(x)\equiv \dfrac{A(x)+B_0^2(x)}{2B_0(x)}\quad (\bmod\ x^n) \\
B(x)\equiv \dfrac{1}{2}[\dfrac{A(x)}{B_0(x)}+B_0(x)]\quad (\bmod\ x^n)
B 2 ( x ) ≡ B 0 2 ( x ) ( m o d x 2 n ) B ( x ) ≡ B 0 ( x ) ( m o d x 2 n ) B ( x ) − B 0 ( x ) ≡ 0 ( m o d x 2 n ) ( B ( x ) − B 0 ( x ) ) 2 ≡ 0 ( m o d x n ) B 2 ( x ) − 2 B ( x ) B 0 ( x ) + B 0 2 ( x ) ≡ 0 ( m o d x n ) A ( x ) − 2 B ( x ) B 0 ( x ) + B 0 2 ( x ) ≡ 0 ( m o d x n ) B ( x ) ≡ 2 B 0 ( x ) A ( x ) + B 0 2 ( x ) ( m o d x n ) B ( x ) ≡ 2 1 [ B 0 ( x ) A ( x ) + B 0 ( x ) ] ( m o d x n )
然后就可以递归求解了,只需要多项式求逆。
多项式除法
给定 n n n 次多项式 F ( x ) F(x) F ( x ) 和 m m m 次多项式 G ( x ) G(x) G ( x ) ,求多项式 Q ( x ) Q(x) Q ( x ) 和 R ( x ) R(x) R ( x ) ,满足 :
大力推式子
F ( x ) = Q ( x ) ∗ G ( x ) + R ( x ) F ( 1 x ) = Q ( 1 x ) ∗ G ( 1 x ) + R ( 1 x ) x n F ( 1 x ) = x n − m Q ( 1 x ) ∗ x m G ( 1 x ) + x n − m + 1 x m − 1 R ( x ) F(x)=Q(x)*G(x)+R(x) \\
F(\frac{1}{x})=Q(\frac{1}{x})*G(\frac{1}{x})+R(\frac{1}{x}) \\
x^nF(\frac{1}{x})=x^{n-m}Q(\frac{1}{x})*x^mG(\frac{1}{x})+x^{n-m+1}x^{m-1}R(x) \\
F ( x ) = Q ( x ) ∗ G ( x ) + R ( x ) F ( x 1 ) = Q ( x 1 ) ∗ G ( x 1 ) + R ( x 1 ) x n F ( x 1 ) = x n − m Q ( x 1 ) ∗ x m G ( x 1 ) + x n − m + 1 x m − 1 R ( x )
我们发现 x n F ( 1 x ) x^nF(\frac{1}{x}) x n F ( x 1 ) 其实就是 F ( x ) F(x) F ( x ) 翻转一下,将其设为 F R ( x ) F_R(x) F R ( x ) ,其余同理。
F R ( x ) = Q R ( x ) ∗ G R ( x ) + x n − m + 1 R R ( x ) F R ( x ) ≡ Q R ( x ) ∗ G R ( x ) ( m o d x n − m + 1 ) Q R ( x ) = F R ( x ) G R ( x ) ( m o d x n − m + 1 ) F_R(x)=Q_R(x)*G_R(x)+x^{n-m+1}R_R(x) \\
F_R(x)\equiv Q_R(x)*G_R(x) \quad (\bmod\ x^{n-m+1}) \\
Q_R(x)=\dfrac{F_R(x)}{G_R(x)}\quad (\bmod\ x^{n-m+1}) \\
F R ( x ) = Q R ( x ) ∗ G R ( x ) + x n − m + 1 R R ( x ) F R ( x ) ≡ Q R ( x ) ∗ G R ( x ) ( m o d x n − m + 1 ) Q R ( x ) = G R ( x ) F R ( x ) ( m o d x n − m + 1 )
多项式求逆即可
有了 Q R ( x ) Q_R(x) Q R ( x ) 也就有了 Q ( x ) Q(x) Q ( x ) ,然后
R ( x ) = F ( x ) − Q ( x ) ∗ G ( x ) R(x)=F(x)-Q(x)*G(x)
R ( x ) = F ( x ) − Q ( x ) ∗ G ( x )
多项式 exp
给定一个多项式 A ( x ) A(x) A ( x ) ,求多项式 B ( x ) B(x) B ( x ) ,满足 B ( x ) ≡ e A ( x ) ( m o d x n ) B(x)\equiv e^{A(x)}\quad (\bmod\ x^n) B ( x ) ≡ e A ( x ) ( m o d x n ) 。系数对 998244353 998244353 9 9 8 2 4 4 3 5 3 取模。
牛顿迭代
对于形如 F ( G ( x ) ) F(G(x)) F ( G ( x ) ) 的复合函数,求满足 F ( G ( x ) ) = 0 F(G(x))=0 F ( G ( x ) ) = 0 的 G ( x ) G(x) G ( x ) 。
G ( x ) = G 0 ( x ) − F ( G 0 ( x ) ) ) F ′ ( G 0 ( x ) ) G(x)=G_0(x)-\dfrac{F(G_0(x)))}{F'(G_0(x))}
G ( x ) = G 0 ( x ) − F ′ ( G 0 ( x ) ) F ( G 0 ( x ) ) )
通过这个式子可以迅速逼近真实值。
在本题中
B ( x ) ≡ e A ( x ) ( m o d x n ) ln B ( x ) ≡ A ( x ) ( m o d x n ) ln B ( x ) − A ( x ) ≡ 0 ( m o d x n ) B(x)\equiv e^{A(x)}\quad (\bmod\ x^n) \\
\ln B(x)\equiv A(x)\quad (\bmod\ x^n) \\
\ln B(x)-A(x)\equiv 0 \quad (\bmod\ x^n) \\
B ( x ) ≡ e A ( x ) ( m o d x n ) ln B ( x ) ≡ A ( x ) ( m o d x n ) ln B ( x ) − A ( x ) ≡ 0 ( m o d x n )
令
F ( G ( x ) ) = ln G ( x ) − A ( x ) F(G(x))=\ln G(x)-A(x)
F ( G ( x ) ) = ln G ( x ) − A ( x )
只需要使
F ( G ( x ) ) ≡ 0 ( m o d x n ) F(G(x))\equiv 0\quad (\bmod\ x^n) \\
F ( G ( x ) ) ≡ 0 ( m o d x n )
其中 G 0 ( x ) G_0(x) G 0 ( x ) 满足
F ( G 0 ( x ) ) ≡ 0 ( m o d x n 2 ) F(G_0(x))\equiv 0 \quad (\bmod\ x^{\frac{n}{2}}) \\
F ( G 0 ( x ) ) ≡ 0 ( m o d x 2 n )
因为对于 F ( G ( x ) ) F(G(x)) F ( G ( x ) ) 来说 G ( x ) G(x) G ( x ) 为自变量,A ( x ) A(x) A ( x ) 相当于一个常量,所以
F ′ ( G ( x ) ) = 1 G ( x ) F'(G(x))=\dfrac{1}{G(x)} \\
F ′ ( G ( x ) ) = G ( x ) 1
那么
G ( x ) = G 0 ( x ) − ( ln G 0 ( x ) − A ( x ) ) ∗ G ( x ) = G 0 ( x ) ∗ ( A ( x ) − ln G 0 ( x ) + 1 ) \begin{aligned}
G(x)&=G_0(x)-(\ln G_0(x)-A(x)) *G(x) \\
&=G_0(x)*(A(x)-\ln G_0(x)+1)
\end{aligned}
G ( x ) = G 0 ( x ) − ( ln G 0 ( x ) − A ( x ) ) ∗ G ( x ) = G 0 ( x ) ∗ ( A ( x ) − ln G 0 ( x ) + 1 )
然后就可以递归处理了,需要多项式 ln。
多项式快速幂
给定一个多项式 A ( x ) A(x) A ( x ) ,求多项式 B ( x ) B(x) B ( x ) ,满足 B ( x ) ≡ A k ( x ) ( m o d x n ) B(x)\equiv A^k(x)\quad (\bmod\ x^n) B ( x ) ≡ A k ( x ) ( m o d x n ) 。系数对 998244353 998244353 9 9 8 2 4 4 3 5 3 取模。
推一下式子
B ( x ) ≡ A k ( x ) ( m o d x n ) ln B ( x ) ≡ k ln A ( x ) ( m o d x n ) B ( x ) ≡ e k ln A ( X ) ( m o d x n ) B(x)\equiv A^k(x)\quad (\bmod\ x^n) \\
\ln B(x)\equiv k\ln A(x)\quad (\bmod\ x^n) \\
B(x)\equiv e^{k\ln A(X)} \quad (\bmod\ x^n)
B ( x ) ≡ A k ( x ) ( m o d x n ) ln B ( x ) ≡ k ln A ( x ) ( m o d x n ) B ( x ) ≡ e k ln A ( X ) ( m o d x n )
只需要多项式 exp 和多项式 ln。
k k k 能取模就感性理解一下吧