拉插
填个坑。
大概是有一个 \(k\) 次多项式 \(f\) ,给 \(k+1\) 组 \((x_i,y_i)\) 满足 \(f(x_i)=y_i\),求\(f\)。显然高消是 \(k^3\) 的。不过我们可以 \(k^2\) 构造一个多项式满足条件,即是:
\[f(x)=\sum_{i=1}^{k+1} y_i \cdot \prod_{j=1,j\neq i}^{k+1} {x-x_j\over x_i-x_j}
\]
证明很简单,我们把每个 \(x_i\) 代进去, 考虑后面那一坨系数, 发现只有可能在乘 \(y_i\) 的时候为 \(1\), 否则一定会有一项的分子是 \(x_i-x_i=0\)。
然后我们就可以 \(k^2\) 求出来了。洛谷上的板子:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 2e3 + 5, mod = 998244353;
int x[N], y[N], n, k;
inline int power(int a, int b) {
int t = 1, y = a, k = b;
while (k) {
if (k & 1) t = (1ll * t * y) % mod;
y = (1ll * y * y) % mod; k >>= 1;
} return t;
}
inline int la(int k) {
int ans = 0;
for (int i = 1; i <= n; ++i) {
int del = 1;
for (int j = 1; j <= n; ++j)
if (j != i) {
del = (1ll * del * (((k - x[j]) % mod + mod) % mod)) % mod;
del = (1ll * del * power(((x[i] - x[j]) % mod + mod) % mod, mod - 2)) % mod;
}
del = (1ll * y[i] * del) % mod;
ans = ans + del;
if (ans >= mod) ans -= mod;
} return ans;
}
int main() {
scanf("%d%d", &n, &k); k %= mod;
if (k < 0) k += mod;
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &x[i], &y[i]);
x[i] %= mod; y[i] %= mod;
if (x[i] < 0) x[i] += mod;
if (y[i] < 0) y[i] += mod;
}
printf("%d", la(k));
return 0;
}
example
CF622F
求:
\[\sum_{i=1}^n i^k \space\space\space\space\space (n\le 1e9, k\le 1e6)
\]
Sol:
很多要用拉插的题其实都是求这个来辅助求值。
它是个\(k+1\)次多项式可以用差分证,考场猜结论的话可以用积分近似出来在 \(n^{k+1}-1\over k+1\) 左右的样子,容易猜到是个 \(k+1\)次多项式。
然后就直接把 \(n=0~k+1\) 的值算出来,带进去就完事了。要注意 \(k\) 很大,但 \(x_i\) 是连续的,可以稍微预处理一下快速求解。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6 + 5, mod = 1e9 + 7;
int fac[N], ifac[N], nfac[N], infac[N], n, k, y[N], suf[N];
inline int power(int a, int b) {
int t = 1, y = a, k = b;
while (k) {
if (k & 1) t = (1ll * t * y) % mod;
y = (1ll * y * y) % mod; k >>= 1;
} return t;
}
inline void pre() {
fac[0] = nfac[0] = 1;
for (int i = 1; i <= k + 1; ++i) {
fac[i] = (1ll * fac[i - 1] * i) % mod;
nfac[i] = (1ll * nfac[i - 1] * (mod - i)) % mod;
} y[0] = 0;
for (int i = 1; i <= k + 1; ++i) {
y[i] = y[i - 1] + power(i, k);
if (y[i] >= mod) y[i] -= mod;
} ifac[k + 1] = power(fac[k + 1], mod - 2);
infac[k + 1] = power(nfac[k + 1], mod - 2);
for (int i = k; ~i; --i) {
ifac[i] = (1ll * ifac[i + 1] * (i + 1)) % mod;
infac[i] = (1ll * infac[i + 1] * (mod - i - 1)) % mod;
} suf[0] = n;
for (int i = 1; i <= k + 1; ++i) suf[i] = (1ll * suf[i - 1] * (((n - i) % mod + mod) % mod)) % mod;
}
inline int lar(int i, int x) {
int ret;// = (1ll * suf * power(((x - i) % mod + mod % mod), mod - 2)) % mod;
if (k + 1 < x) ret = (1ll * suf[k + 1] * power(((x - i) % mod + mod % mod), mod - 2)) % mod;
else if (k + 1 >= x) {
if (i != x) return 0;
ret = (1ll * suf[x - 1] * nfac[k + 1 - x]) % mod;
}
ret = (1ll * ret * infac[k + 1 - i]) % mod;
ret = (1ll * ret * ifac[i]) % mod;
return ret;
}
int main() {
scanf("%d%d", &n, &k);
pre(); int ans = 0;
for (int i = 0; i <= k + 1; ++i) {
ans = ans + ((1ll * y[i] * lar(i, n)) % mod);
if (ans >= mod) ans -= mod;
if (ans < 0) ans += mod;
} printf("%d", ans);
return 0;
}
好像就没啥好说的了。

浙公网安备 33010602011771号