多项式——乘法逆元
多項式——乘法逆元
給定一個多項式 F(x)F(x)F(x) ,請求出一個多項式 G(x)G(x)G(x) 滿足 F(x)G(x)≡1modxnF(x)G(x) \equiv 1 \mod x^nF(x)G(x)≡1modxn 。系數對 998244353998244353998244353 取模。
P4238 【模板】多項式乘法逆
本文只介紹遞推的方法,首先將 nnn 補齊到 2 的冪次,當 n=1n = 1n=1 的時候,多項式中只有一項,那么 [x0]G(x)[x^0]G(x)[x0]G(x) 就是 [x0]F(x)[x^0]F(x)[x0]F(x) 的乘法逆元。
假設我們已知 F(x)H(x)≡1modxn2F(x)H(x) \equiv 1 \mod x^{\frac{n}{2}}F(x)H(x)≡1modx2n? ,那么顯然 F(x)G(x)≡1modxn2F(x) G(x) \equiv 1 \mod x^{\frac{n}{2}}F(x)G(x)≡1modx2n? ,那么 F(x)[G(x)?H(x)]≡0modxn2F(x)[G(x) - H(x)] \equiv 0 \mod x^{\frac{n}{2}}F(x)[G(x)?H(x)]≡0modx2n?,即 G(x)?H(x)≡0modxn2G(x) - H(x) \equiv 0 \mod x^{\frac{n}{2}}G(x)?H(x)≡0modx2n? 。
兩邊同時平方得到 G(x)2+H(x)2?2G(x)H(x)≡0modxnG(x)^2 + H(x)^2 -2G(x)H(x) \equiv 0 \mod x^nG(x)2+H(x)2?2G(x)H(x)≡0modxn ,這是因為原來是 xn2x^{\frac{n}{2}}x2n? 的倍數,平方之后一定也是 xnx^nxn 的 倍數。
最后,兩邊同時乘以 F(x)F(x)F(x) 使得 G(x)2G(x)^2G(x)2 項降冪,因為 F(x)G(x)≡1modxnF(x)G(x) \equiv 1 \mod x^nF(x)G(x)≡1modxn 最后得到:
G(x)≡2H(x)?F(x)H(x)2modxnG(x) \equiv 2H(x) - F(x)H(x)^2 \mod x^n G(x)≡2H(x)?F(x)H(x)2modxn
用 NTT 來加速多項式乘法,時間復雜度為 O(nlog?n)O(n \log n)O(nlogn) 。
#include <bits/stdc++.h>using namespace std;using ll = long long;#ifdef LLT_DBG #define FR freopen("in.txt", "r", stdin) #else #define FR #endiftemplate <ll P> ll fpow(ll a, ll b) {ll res = 1;for (; b; b >>= 1, a = (a * a) % P)if (b & 1)res = (res * a) % P;return res; }template <ll G, ll P> struct NTT {int _n;int E;vector<int> rev;/*** @brief 構建一個 NTT 計算器** @param n 多項式最高項數*/NTT(int n){_n = 1;E = 0;while (_n < n){_n <<= 1;E++;}rev.resize(_n);// 逆位置對換for (int i = 1; i < _n; i++){rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (E - 1));}}void _rNTT(ll A[], ll k){for (int i = 0; i < _n; i++)if (i < rev[i])swap(A[i], A[rev[i]]);for (int e = 1; e <= E; e++){int m = 1 << e;for (int i = 0; i < _n; i += m){int hf = m / 2;ll g = 1;ll gn = fpow<P>(fpow<P>(G, (P - 1) / m), k);for (int j = 0; j < hf; j++){ll x = A[i + j];ll y = (A[i + j + hf] * g) % P;A[i + j] = (x + y) % P;A[i + j + hf] = (x - y) % P;g = (g * gn) % P;}}}}/*** @brief NTT 過程** @param A 系數數組*/void doNTT(ll A[]){_rNTT(A, 1);}/*** @brief NTT 逆過程** @param A 點值數組*/void doINTT(ll A[]){ll ni = fpow<P>(_n, P - 2);_rNTT(A, P - 2);for (int i = 0; i < _n; i++)A[i] = (A[i] * ni) % P;} };ll A[500005]; ll F[500005]; ll B[500005]; ll G[500005];const int mod = 998244353;void solve() {int n;cin >> n;for (int i = 0; i < n; i++){cin >> A[i];}// 初始步驟G[0] = fpow<mod>(A[0], mod - 2);// 歸納步驟int i = 1;while (i < n){i <<= 1;for (int j = 0; j < i; j++)B[j] = 0;// 注意最大界為 2ifor (int j = 0; j < (i >> 1); j++)B[j] = G[j];for (int j = 0; j < i; j++)F[j] = A[j];NTT<3, mod> ntt(i << 1);ntt.doNTT(F);ntt.doNTT(B);for (int j = 0; j < (i << 1); j++)B[j] = B[j] * B[j] % mod * F[j] % mod;ntt.doINTT(B);for (int j = 0; j < i; j++){G[j] = (2 * G[j] % mod - B[j]) % mod;G[j] = (G[j] + mod) % mod;}}for (int i = 0; i < n; i++){G[i] = (G[i] + mod) % mod;cout << G[i] << " ";} }int main() {FR;solve();return 0; }總結
- 上一篇: 思科无边界ip电话配置方案
- 下一篇: Oc 二维码的扫描-ZBar与生成