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