【学习笔记】拉格朗日插值入门
2026-02-01 14:54:46
发布于:山东
同步发布于 我的 cnblogs
这篇应该比较简单()
Lagrange 插值
给出 个点 满足 ,可以唯一确定一个 次多项式 过上述所有 个点。
现在给出 ,求 的值。
一个简单的想法是直接 Gauss 消元,可以 解出这个 次多项式每一项的系数。
这里介绍一下用 Lagrange 插值的解法:
- 构造 个函数 表示该函数过点 ,对于任意 都过点 。容易发现令 就可以得到一个满足条件的函数 。
- 然后考虑构造因式分解:对于每个 多项式构造一项 ,然后凑一个系数 满足 ,容易解方程得到 。
- 于是有:,可以在 的时间复杂度内求解。
:::success[ 解法]
inline void main([[maybe_unused]] int _ca, [[maybe_unused]] int atc)
{
cin >> n >> k;
for (int i = 1; i <= n; ++i)
cin >> x[i] >> y[i];
int sum = 0;
for (int i = 1; i <= n; ++i)
{
int inner_product = y[i];
for (int j = 1; j <= n; ++j)
if (i != j)
inner_product = inner_product * (k - x[j] + mod) % mod * inversion(x[i] - x[j] + mod) % mod;
sum = (sum + inner_product) % mod;
}
cout << sum << '\n';
}
:::
:::success[ 解法]
int x[N], y[N], n, k;
inline void main([[maybe_unused]] int _ca, [[maybe_unused]] int atc)
{
cin >> n >> k;
for (int i = 1; i <= n; ++i)
cin >> x[i] >> y[i];
int sum = 0;
for (int i = 1; i <= n; ++i)
{
int product_numerator = y[i], product_denominator = 1;
for (int j = 1; j <= n; ++j)
if (i != j)
product_numerator = product_numerator * (k - x[j] + mod) % mod,
product_denominator = product_denominator * (x[i] - x[j] + mod) % mod;
sum = (sum + product_numerator * inversion(product_denominator) % mod) % mod;
}
cout << sum << '\n';
}
:::
001. P5667 拉格朗日插值2
根据上面的理论,容易得到:
可以 时间复杂度求解。
考虑对这个东西进行优化。注意到 的取值是连续的一段,所以从这里突破:
记 ,则可以用 NTT 求出 即 为 两个序列的等差卷积,而 显然可以线性递推。
但是这真的对吗???把卷积形式写出来之后发现其形如:(),这怎么还出来负数下标了()不过解决这个问题也是简单的,重新记 ,此时有 ,将其写成卷积的形式只需要对所有 都记 就可以扩展为 的形式。
一次 NTT 卷积即可求出 这个等差卷积。
因此总时间复杂度为 ,分段打表阶乘可以把后面的 省去。
跑了 973ms,喜提最劣解(没事至少这个能过)
:::success[Code]
// #pragma GCC optimize(3, "Ofast", "inline", "unroll-loops")
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1100010;
const int mod = 998244353;
const int inf = 1e18;
using ld = long double;
using ull = unsigned long long;
using i128 = __int128;
const ull base = 13331;
namespace Luminescent
{
const double pi = acos(-1);
const ld pi_l = acosl(-1);
struct DSU
{
int fa[N];
inline DSU() { iota(fa, fa + N, 0); }
inline void init(int maxn) { iota(fa, fa + maxn + 1, 0); }
inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inline int merge(int x, int y)
{
x = find(x), y = find(y);
if (x != y)
return fa[x] = y, 1;
return 0;
}
};
inline void add(int &x, int a) { x = (x + a) % mod; }
inline void sub(int &x, int a) { x = (x - a + mod) % mod; }
inline int power(int a, int b, int c)
{
int sum = 1;
while (b)
{
if (b & 1)
sum = 1ll * sum * a % c;
a = 1ll * a * a % c, b >>= 1;
}
return sum;
}
inline int inversion(int x) { return power(x, mod - 2, mod); }
inline int inversion(int x, int mod) { return power(x, mod - 2, mod); }
inline int varphi(int x)
{
int phi = 1;
for (int i = 2; i * i <= x; ++i)
if (x % i == 0)
{
phi *= (i - 1);
x /= i;
while (x % i == 0)
phi *= i, x /= i;
}
if (x > 1)
phi *= (x - 1);
return phi;
}
}
using namespace Luminescent;
namespace Poly
{
const int g = 3;
int rev[N];
void ntt(int *a, int n, int mode)
{
int bit = 1;
while ((1 << bit) < n)
++bit;
for (int i = 0; i < n; ++i)
{
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
if (i < rev[i])
swap(a[i], a[rev[i]]);
}
for (int l = 2; l <= n; l <<= 1)
{
int x = power(g, (mod - 1) / l, mod);
if (mode == 1)
x = inversion(x);
for (int i = 0; i < n; i += l)
{
int v = 1;
for (int j = 0; j < l / 2; ++j, v = v * x % mod)
{
int v1 = a[i + j], v2 = a[i + j + l / 2] * v % mod;
a[i + j] = (v1 + v2) % mod, a[i + j + l / 2] = (v1 - v2 + mod) % mod;
}
}
}
}
// calc convolution: c[i] = \sum\limits_{j=0}^i (a[j] * b[i - j])
void convolution(int *a, int n, int *b, int m, int *c)
{
int tn = n, tm = m;
n = n + m + 2;
while (__builtin_popcount(n) > 1)
++n;
// cerr << "n = " << n << '\n';
for (int i = tn + 1; i <= n + 1; ++i)
a[i] = 0;
for (int i = tm + 1; i <= n + 1; ++i)
b[i] = 0;
ntt(a, n, 0), ntt(b, n, 0);
for (int i = 0; i < n; ++i)
c[i] = a[i] * b[i] % mod;
ntt(c, n, 1);
const int inv_n = inversion(n);
for (int i = 0; i <= n + m; ++i)
c[i] = c[i] * inv_n % mod;
}
}
namespace Loyalty
{
inline void init() { }
int y[N], n, m;
int fac[N], inv[N], ifac[N];
int A[N], B[N], C[N], P[N];
inline void main([[maybe_unused]] int _ca, [[maybe_unused]] int atc)
{
cin >> n >> m;
for (int i = 0; i < 2; ++i)
fac[i] = inv[i] = ifac[i] = 1;
for (int i = 2; i < N; ++i)
{
fac[i] = fac[i - 1] * i % mod;
inv[i] = mod - inv[mod % i] * (mod / i) % mod;
ifac[i] = ifac[i - 1] * inv[i] % mod;
}
for (int i = 0; i <= n; ++i)
cin >> y[i];
auto coef = [&](int x) { return (x & 1) ? (mod - 1) : 1; };
for (int i = 0; i <= n; ++i)
A[i] = ifac[i] * y[i] % mod * coef(n - i) % mod * ifac[n - i] % mod;
for (int i = 0; i <= n + n; ++i)
B[i] = inversion(m + i - n);
Poly::convolution(A, n + n, B, n + n, C);
int fac_m = 1, ifac_m = 1;
for (int i = 2; i <= m; ++i)
fac_m = fac_m * i % mod;
for (int i = 2; i <= m - n - 1; ++i)
ifac_m = ifac_m * i % mod;
ifac_m = inversion(ifac_m);
for (int k = 0; k <= n; ++k)
{
P[k] = fac_m * ifac_m % mod;
fac_m = fac_m * (m + k + 1) % mod;
ifac_m = ifac_m * inversion(m + k - n) % mod;
}
for (int k = 0; k <= n; ++k)
cout << C[n + k] * P[k] % mod << ' ';
cout << '\n';
}
}
signed main()
{
// freopen("1.in", "r", stdin);
// freopen("1.out", "w", stdout);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
int T = 1;
// cin >> T;
Loyalty::init();
for (int ca = 1; ca <= T; ++ca)
Loyalty::main(ca, T);
return 0;
}
:::
006. CF622F The Sum of the k-th Powers
通过作差可以发现答案是一个 次多项式的形式,因此想到 Lagrange 插值。将 ()带入,有:
后面这两个 一看就很能预处理,而前面的显然可以直接算。时间复杂度为 。注意到 是积性函数,所以使用线性筛可以将其优化至严格 求解。
007. P4593 [TJOI2018] 教科书般的亵渎
设 ,则容易观察到该题要求的答案为:。后半部分可以暴力快速幂求解,而前半部分是 CF622F,直接套用上面的公式求解即可。
全部评论 223
ddd
2026-02-02 来自 广东
40d
2026-02-01 来自 广东
40d
2026-02-05 来自 广东
24d
2026-02-06 来自 浙江
19d
1周前 来自 浙江
5
ddd
2026-02-01 来自 上海
29d
2026-02-06 来自 浙江
6
d
2026-02-02 来自 广东
21d
2026-02-02 来自 广东
15d
2026-02-05 来自 广东
5
帖主似乎并没有发现
:::success[]语法是无法在 ACGO 使用的
2026-02-03 来自 浙江
14(((
2026-02-03 来自 浙江
11似乎我发现了
2026-02-03 来自 北京
11666
2026-02-07 来自 浙江
4
要不是我帖子热度太高不舍得,我都想删了让你上榜
2026-02-04 来自 上海
11666
2026-02-07 来自 浙江
1
太好叻找到会这个的人叻
2026-02-01 来自 上海
9NB
2026-02-05 来自 上海
8d
2026-02-05 来自 广东
3d
2026-02-06 来自 浙江
3
ddd
2026-02-03 来自 浙江
8ddd
2026-02-03 来自 浙江
8ddd
2026-02-03 来自 浙江
9ddd
2026-02-03 来自 浙江
9
666
2026-02-03 来自 广东
8为攒罐头,硬着头皮点个赞,发评论
2026-02-04 来自 浙江
7顶
2026-02-04 来自 浙江
5



2026-02-04 来自 浙江
5d
2026-02-05 来自 四川
4
这其实是在学编程
2026-02-04 来自 浙江
5何意味
2026-02-04 来自 重庆
2疑似需要折寿才能看懂

1周前 来自 浙江
2
高质不火?
2026-02-04 来自 上海
466
2026-02-07 来自 浙江
2
d
2026-02-04 来自 浙江
41
2026-02-04 来自 广东
4666
2026-02-04 来自 浙江
4ddd
2026-02-04 来自 浙江
31
2026-02-04 来自 浙江
31
2026-02-03 来自 上海
3




























































有帮助,赞一个