[拉格朗日插值]CF622F The Sum of the k-th Powers 题解

好题,基本没有高级知识但是依然能把蒟蒻如我绕的晕头转向

前置知识:拉格朗日插值

这个东西其实也比较简单,一个 n 次多项式,给你 n + 1 个平面上的点,就能求出一条图像

形式化的讲就是下面这个东西

\[f(x) = \sum_{i=0}^{N} y_i \prod_{i\ne j}\frac{x - x_i}{x_i - x_j} \]

如果有兴趣可以到我主页找详细讲推法的文章

回到本题,我么首先要证一下 \(\sum_{i = 1}^{n} i ^ k\) 是个 k + 1 次多项式

这个拿差分做一下?发现 \(\sum_{i=1}^{n} i ^ k- \sum_{i=1}^{n - 1} i ^ k\) 差分出来是一个 k 次多项式,由于差分后的次数是会降一次(这个我不知道别人是怎么理解的,我反正是从因式分解角度想了一下,发现还挺显然的,书面证明可以看洛谷题解第一篇),所以就是k + 1次多项式

那是不是就证完了,所以我们要取k + 2个点

显然,这道题平面上点的横坐标是题目中给定的 \(i\) (所以 \(x_i\) 就是 \(i\) ), 纵坐标就是 \(\sum_{i = 1}^{n} i ^k\) 。为了方便后续操作,这 k + 2 个点咱们取成连续的。那么答案就是 \(f(n)\)

\[Ans = f(n) = \sum_{i = 0}^{N} y_i \prod_{i \ne j}\frac{n - i}{i - j} \]

这个东西看着比较丑但是实际上还好,由于 k 是 1e6 范围,\(\sum_{i = 0}^{N} y_i\) 我们不用管预处理后面这个玩意即可

上面一层是 $$\prod_{i = 1}^{j - 1} (n - i) \prod_{i = j + 1}^{k + 2}(n - i)$$

下面一层是 $$\prod_{i = 1}^{j - 1} (i - j) \prod_{i = j + 1}^{k + 2}(i - j)$$

那是不是分别预处理一下这两层和那个 \(y\) 就好了。好消息,这个题的取模没有什么恶心人的点。复杂度 \(O(k\log k)\)

#include <bits/stdc++.h>

#define inv(x)(Pow(x , mod - 2))
typedef long long ll;
const int N = 1e6 + 7;
const ll mod = 1e9 + 7;

namespace cf662F {
	using namespace std;
	ll n , k , ans = 0 , y[N] , fac[N] , fac_[N] , factorial[N] , neg_factorial[N];
	
	inline ll Pow(ll a , ll b) {
		ll ans = 1;
		while(b) {
			if(b & 1) {
				ans = ans * a % mod;
			}
			a = a * a % mod , b >>= 1;
		}	return ans % mod;
	}
	
	void init() {
		fac[0] = factorial[0] = neg_factorial[0] = 1;
		for(register ll i = 1; i <= k + 2; ++i) {
			y[i] = (y[i - 1] + Pow(i , k)) % mod;
			fac[i] = fac[i - 1] * i % mod; 
			factorial[i] = factorial[i - 1] * (n - i) % mod;
			neg_factorial[i] = (-neg_factorial[i - 1] * i + mod) % mod;
		}
		fac_[k + 3] = 1;
		for(register ll i = k + 2; i; --i) {
			fac_[i] = fac_[i + 1] * (n - i) % mod;
		}
	}
	
	void solve() {
		ios :: sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
		cin >> n >> k , init();
		
		for(register ll i = 0; i <= k + 2; ++i) {
			ll up = factorial[i - 1] * fac_[i + 1] % mod;
			ll down = fac[i - 1] * neg_factorial[abs(i - k - 2)] % mod;
			ans = (ans % mod + y[i] * up % mod * inv(down) % mod + mod) % mod;
		}
		cout << ans << '\n';
	}
}

int main() {
	cf662F :: solve(); return 0;
}
posted @ 2025-03-19 00:20  「癔症」  阅读(14)  评论(0)    收藏  举报