Loading

P5667 拉格朗日插值2

由拉格朗日插值公式得:

\[f(x) = \sum_{i = 0}^nf(i)\prod_{j \ne i}\dfrac{x - j}{i - j} = \sum_{i = 0}^n\dfrac{f(i)x^{\underline{n+1}}}{(-1)^{n-i}i!(n - i)!(x - i)} \]

我们要把函数平移 \(m\) 个单位长度,所以要写 \(f(x + m)\) 的式子,即

\[f(x + m) = \sum_{i = 0}^n\dfrac{f(i)(x+m)^{\underline{n+1}}}{(-1)^{n-i}i!(n - i)!(x + m - i)} \]

\(A(x) = \begin{cases}\frac{f(x)}{(-1)^{n-x}x!(n - x)!} & x \le n \\ 0 & x > n\end{cases}, B(x) = \dfrac1{x + m}, F = A * B\)

\(x \le n\) 时,有:

\[F(x) = \sum_{i=0}^xA(i)B(x - i) = \sum_{i = 0}^x\dfrac{f(i)}{(-1)^{n-i}i!(n-i)!(x+m-i)} \]

你会发现这样少算了 \([x + 1, n]\) 里的信息,所以 \(B(x)\) 需要平移一下,变为 \(B(x) = \dfrac1{x + m - n}\)

对于 \(x \le n\),有:

\[F(x+n) = \sum_{i=0}^nA(i)B(x+n-i) = \sum_{i=0}^n\dfrac{f(i)}{(-1)^{n-i}i!(n-i)!(x+m-i)} \]

所以有

\[f(x + m) = (x+m)^{\underline{n+1}}F(x+n) \]

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

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

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

int n, m, f[N], A[N], B[N], F[N];
int bits, len, rev[N], Wn[2][19];
ll invfct[N], down[N];

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;
}

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);
}

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

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[i];

    for (int i = 0; i < 19; i++) Wn[0][i] = qp(3, (MOD - 1) / (1 << (i + 1))), Wn[1][i] = qp(Wn[0][i], MOD - 2);
    invfct[0] = 1; for (int i = 1; i <= n; i++) invfct[i] = invfct[i - 1] * i % MOD;
    for (int i = 2; i <= n; i++) invfct[i] = qp(invfct[i], MOD - 2);
    down[0] = 1; for (int i = m; i >= m - n; i--) down[0] = down[0] * i % MOD;
    for (int i = 1; i <= n; i++) down[i] = down[i - 1] * qp(m - n + i - 1, MOD - 2) % MOD * (m + i) % MOD;

    for (int i = 0; i <= n; i++) {
        A[i] = f[i] * invfct[i] % MOD * invfct[n - i] % MOD;
        if ((n ^ i) & 1) A[i] = MOD - A[i];
    }
    for (int i = 0; i <= (n << 1); i++) B[i] = qp(i + m - n, MOD - 2);

    init((n << 1) + 1); NTT(A), NTT(B);
    for (int i = 0; i < len; i++) F[i] = (ll)A[i] * B[i] % MOD;
    NTT(F, 1);
    for (int i = 0; i <= n; i++) cout << down[i] * F[i + n] % MOD << ' ';
    return 0;
}
posted @ 2024-02-13 15:51  Chy12321  阅读(49)  评论(0编辑  收藏  举报