拉插

填个坑。

大概是有一个 \(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;
}

好像就没啥好说的了。

posted @ 2021-03-12 21:33  Smallbasic  阅读(30)  评论(0)    收藏  举报