P4512 【模板】多项式除法

为什么不能直接用 \(F(x) \times G(x)^{-1}\) 做?

\(G(x)^{-1}\) 是模 \(x^{m+1}\) 意义下的,\(n - m > m\) 时得到的 \(Q(x)\) 就是错的。

\(F'(x)\)\(F(x)\) 系数翻转后的多项式,即若 \(F(x) = \sum\limits_{i = 0}^nf_ix^i\),则 \(F'(x) = \sum\limits_{i = 0}^nf_{n - i}x^i = \sum\limits_{i = 0}^nf_ix^{n - i}\)

\[F'(x) = x^nF(\dfrac1x) \]

\(G'(x), Q'(x), R'(x)\) 同理。

然后开始推式子,目标是把模 \(x^{m+1}\) 替换为模 \(x^{n-m+1}\)

代入 \(\dfrac1x\),得

\[F(\dfrac1x) = Q(\dfrac1x) * G(\dfrac1x) + R(\dfrac 1x) \]

同乘 \(x^n\),注意 \(Q(\dfrac1x) * G(\dfrac1x)\) 的次数正好是 \(n\)\(R(\dfrac1x)\) 的次数不大于 \(m - 1\),得

\[F'(x) = Q'(x) * G'(x) + x^{n-m+1}R'(x) \]

其实到这就已经推完了,加个模意义就好

\[F'(x) \equiv Q'(x) * G'(x) \pmod{x^{n-m+1}} \]

也即

\[Q'(x) = F'(x) * G'(x)^{-1} \pmod{x^{n-m+1}} \]

求出 \(Q(x)\) 之后用 \(F(x) = Q(x) * G(x) + R(x) \Rightarrow R(x) = F(x) - Q(x) * G(x)\) 求出 \(R(x)\) 即可。

时间复杂度是 \(\mathcal O(n \log n)\)

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

constexpr int N = 1 << 18, MOD = 998244353;

int n, m, f[N], g[N], r[N], q[N];
int bits, len, rev[N], Wn[2][18];

ll qp(ll base, int e = MOD - 2) {
    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 = Wn[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);
        for (int i = 0; i < len; i++) A[i] = A[i] * invlen % MOD;
    }
}

inline void init(int n) {
    bits = -1, len = 1; while (len < n) len <<= 1, bits++;
    for (int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bits);
}

int tmp[N];
void getinv(int n, int *const res, const int * f) {
    if (n == 1) {res[0] = qp(f[0]); return;}
    getinv((n + 1) >> 1, res, f);
    init((n << 1) - 1); memcpy(tmp, f, n << 2), fill(tmp + n, tmp + len, 0); NTT(tmp), NTT(res);
    for (int i = 0; i < len; i++) res[i] = res[i] * ((2 - (ll)tmp[i] * res[i]) % MOD + MOD) % MOD;
    NTT(res, 1); fill(res + n, res + len, 0);
}

int main() {
    ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
    cin >> n >> m;
    for (int i = 0; i <= n; i++) cin >> f[n - i];
    for (int i = 0; i <= m; i++) cin >> g[m - i];
    for (int i = 0; i < 18; i++) Wn[0][i] = qp(3, (MOD - 1) / (1 << (i + 1))), Wn[1][i] = qp(Wn[0][i], MOD - 2);
    n++, m++; getinv(n - m + 1, q, g);
    init((n << 1) - 1); memcpy(tmp, f, len << 2); NTT(q), NTT(tmp);
    for (int i = 0; i < len; i++) q[i] = (ll)q[i] * tmp[i] % MOD;
    NTT(q, 1); fill(q + n - m + 1, q + len, 0), reverse(q, q + n - m + 1);
    for (int i = 0; i <= n - m; i++) cout << q[i] << ' '; cout << '\n';
    reverse(f, f + n), reverse(g, g + m); init(n); NTT(g), NTT(q);
    for (int i = 0; i < len; i++) r[i] = (ll)g[i] * q[i] % MOD;
    NTT(r, 1); for (int i = 0; i < m; i++) r[i] = (f[i] - r[i] + MOD) % MOD;
    for (int i = 0; i < m - 1; i++) cout << r[i] << ' ';
    return 0;
}

作者:chy12321

出处:https://www.cnblogs.com/chy12321/p/18013955

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Chy12321  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题