Codeforces 622 F. The Sum of the k-th Powers
题目大意 : 给出 \(n, k\),求 \(\sum_{i=1}^{n} i^k\) 对 \(10^9 +7\) 取模的值
\(1 \leq n \leq 10^9, 0 \leq k \leq 10^6\)
解题思路 :
考虑 \(k\) 比较大,且模数不太好 \(NTT\),于是考虑插值做法, 学习了一波插值之后,发现就是个板子题 (雾)
拉格朗日插值:
对于 \(n\) 个点值表达,可以确定一个 \(n - 1\) 次的多项式,考虑已知点值怎么构造这个多项式
如果对于第 \(i\) 个点值,能够构造出这么一个多项式 \(f_i(x)\) ,将每一个点值表达 \(j\) 带进去的结果如下
\[f_i (x) = \begin{cases} y_i , & \text{if $ i= j$} \\ 0. \, & \text{otherwise} \end{cases} \]那么最终的多项式 \(F(x) = \sum_{i=1}^{n} f_i(x)\)
通过贺资料发现当 $f_i(x) = y_i \times \prod_{j=1, \ j \neq i}^{n} \frac{x-x_j}{x_i-x_j} $ 时即可满足条件,不妨证明一下为什么
考虑分子部分,如果带进去的 \(x \neq x_i\) 那么当 \(j = i\) 的时候分子是 \(0\),结果也是 \(0\)
考虑分母部分,如果 \(x = x_i\) 那么分子就等于分母,且分子分母都不存在 \(0\) ,所以结果就是 \(y_i\)
大力观察题面发现,\(k\) 次幂的前缀和一定能用一个 \(k + 1\) 次的多项式来表示,不妨递推出 \(x = 1\ .. \ (k+2)\) 时的点值表示直接做插值
那么第 \(n\) 项的答案就等于 $F(n) = \sum y_i \times \prod_{j=1, \ j \neq i}^{k+2} \frac{n-x_j}{x_i-x_j} $
因为 \(x_i = i\) ,所以 \(F(n) = \sum y_i \times \prod_{j=1, \ j \neq i}^{k+2} \frac{n-j}{i-j}\), 后面部分也就是 \(\frac{(n-1)\times(n-2)\times..\times(n-k-2)}{(n-i)\times(i-1)!\times(n-i)!\times (-1)^{n-i}}\)
那么阶乘与处理一下枚举一下 \(i\) 即可,注意特判一下 \(i = n\) 的情况不能直接除,应该记一个没有 \((n-i)\) 这一项的答案
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define int ll
int js[2000005], n, k;
const int Mod = 1000000007;
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = a * a % Mod)
if(b & 1) ans = ans * a % Mod;
return ans;
}
inline int Inv(int x){ return Pow((x + Mod) % Mod, Mod - 2); }
main(){
int res = 1, res2 = 1; read(n), read(k), js[0] = 1;
for(int i = 1; i <= k + 2; i++){
js[i] = (js[i-1] * i) % Mod;
res = (res * (n - i) + Mod) % Mod;
if(i != n) res2 = (res2 * (n - i) % Mod + Mod) % Mod;
}
int now = 0, ans = 0;
for(int i = 1; i <= k + 2; i++){
now = (now + Pow(i, k)) % Mod;
int A = (i != n) ? res * Inv(n - i) % Mod : res2;
int B = js[i-1] * js[k+2-i] % Mod;
if((k + 2 - i) & 1) B = (-B + Mod) % Mod;
ans = (ans + now * (A * Inv(B) % Mod) % Mod) % Mod;
}
cout << (ans % Mod + Mod) % Mod;
return 0;
}