多项式求逆
类似于逆原,多项式也可以求逆,具体地,定义多项式 \(f(x)\) 的乘法逆为能使得 \(f(x) * g(x) \equiv 1 \pmod{x^n}\) 的多项式 \(g(x)\),也可记作 \(f(x)^{-1}\)。
假设我们现在已经求出了 \(f(x)\) 在模 \(x^{\lceil\frac n2\rceil}\) 意义下的逆原 \(f_0(x)^{-1}\)。有:
\[\left.\begin{aligned}
f(x)f_0(x)^{-1} \equiv 1 \pmod{x^{\lceil\frac n2\rceil}} \\
f(x)f(x)^{-1} \equiv 1 \pmod{x^{\lceil\frac n2\rceil}}
\end{aligned}\right\} \Rightarrow f(x)^{-1} - f_0(x)^{-1} \equiv 0 \pmod{x^{\lceil\frac n2\rceil}}
\]
两边平方,得:
\[f(x)^{-2} - 2f^{-1}(x)f_0(x)^{-1} + f_0(x)^{-2} \equiv 0 \pmod{x^n}
\]
两边同乘 \(f(x)\),得:
\[f(x)^{-1} \equiv f_0(x)^{-1}[2 - f(x)f_0(x)^{-1}] \pmod{x^n}
\]
递归下去就好了,时间复杂度 \(T(n) = T(\dfrac n2) + \mathcal O(n \log n) = \mathcal O(n \log n)\)。常数很小。
特别地,\(f(x)^{-1} \equiv f(0)^{-1} \pmod x\)。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr int N = 1 << 18, MOD = 998244353;
int n, f[N], g[N], fg[N];
int len, bits, rev[N], G[2][18];
ll qp(ll base, int e) {
ll res = 1;
while (e) {
if (e & 1) res = res * base % MOD;
base = base * base % MOD;
e >>= 1;
}
return res;
}
void NTT(int *A, bool I = 0) {
for (int i = 0; i < len; i++) if (i < rev[i]) swap(A[i], A[rev[i]]);
for (int i = 1; i < len; i <<= 1) {
ll wn = G[I][__builtin_ctz(i)];
for (int j = 0; j < len; j += (i << 1)) {
ll w = 1;
for (int k = j; k < j + i; k++) {
int t = w * A[k + i] % MOD;
A[k + i] = (A[k] - t + MOD) % MOD, A[k] = (A[k] + t) % MOD;
w = w * wn % MOD;
}
}
}
if (I) {
ll invlen = qp(len, MOD - 2);
for (int i = 0; i < len; i++) A[i] = A[i] * invlen % MOD;
}
}
void solve(int e) {
if (e == 1) return;
solve((e + 1) >> 1);
bits = -1, len = 1; while (len < (e << 1) - 1) len <<= 1, bits++;
for (int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bits);
memcpy(fg, f, e << 2), fill(fg + e, fg + len, 0); NTT(fg), NTT(g);
for (int i = 0; i < len; i++) fg[i] = (ll)fg[i] * g[i] % MOD;
for (int i = 0; i < len; i++) g[i] = (ll)g[i] * (2 - fg[i] + MOD) % MOD;
NTT(g, 1); fill(g + e, g + len, 0);
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
cin >> n; for (int i = 0; i < n; i++) cin >> f[i];
for (int i = 0; i < 18; i++) G[0][i] = qp(3, (MOD - 1) / (1 << (i + 1))), G[1][i] = qp(G[0][i], MOD - 2);
g[0] = qp(f[0], MOD - 2); solve(n);
for (int i = 0; i < n; i++) cout << g[i] << ' ';
return 0;
}
作者:chy12321
出处:https://www.cnblogs.com/chy12321/p/18010730
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现