CONTENT: 拉格朗日插值法 I
DETAIL: 拉格朗日插值法、i^k的前缀和
Introduction
- 拉格朗日插值法
https://zh.wikipedia.org/wiki/%E6%8B%89%E6%A0%BC%E6%9C%97%E6%97%A5%E6%8F%92%E5%80%BC%E6%B3%95 - 线性求逆元
http://blog.miskcoo.com/2014/09/linear-find-all-invert - 多项式前缀和
http://aequa.me/index.php/2018/02/01/powersum-linear/
Note
【模板】拉格朗日插值 - luogu P4781
Description
由小学知识可知,n个点(xi,yi)可以唯一地确定一个多项式
现在,给定n个点,请你确定这个多项式,并将k代入求值
求出的值对998244353取模
Sample Input
3 100
1 4
2 9
3 16
3 100
1 1
2 2
3 3
Sample Output
10201
100
Solution
// luogu-judger-enable-o2
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MOD = 998244353;
const int N = 2000 + 15;
int x[N], y[N];
int quickPow(int a, int b, int MOD) {
int ans = 1, base = a;
while(b) {
if(b & 1) {
ans = (ll)ans * base % MOD;
}
base = (ll)base * base % MOD;
b >>= 1;
}
return ans;
}
inline int calc(int k, int n) {
int sum = 0;
for(int i = 1; i <= n; i++) {
int cur = y[i];
for(int j = 1; j <= n; j++) {
if(i == j) {
continue;
}
cur = (ll)cur * (k - x[j] + MOD) % MOD * quickPow((x[i] - x[j] + MOD) % MOD, MOD - 2, MOD) % MOD;
}
sum = (sum + cur) % MOD;
}
return sum;
}
int main() {
int n, k;
while(~scanf("%d%d", &n, &k)) {
for(int i = 1; i <= n; i++) {
scanf("%d%d", &x[i], &y[i]);
}
printf("%d\n", calc(k, n));
}
}
序列求和 V4 - 51NOD 1258
Description
T(n) = n^k,S(n) = T(1) + T(2) + …… T(n)。给出n和k,求S(n)。
例如k = 2,n = 5,S(n) = 1^2 + 2^2 + 3^2 + 4^2 + 5^2 = 55。
由于结果很大,输出S(n) Mod 1000000007的结果即可。
Sample Input
3
5 3
4 2
4 1
Sample Output
225
30
10
Solution
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MOD = 1000000007;
const int N = 50000 + 15;
int inv[N];
int prime[N], tot;
int fi[N];
int ans[N];
inline int quickPow(int a, int b) {
int ans = 1, base = a;
while(b) {
if(b & 1) {
ans = (ll)ans * base % MOD;
}
base = (ll)base * base % MOD;
b >>= 1;
}
return ans;
}
inline void initInv() {
inv[1] = 1;
for(int i = 2; i < N; i++) {
inv[i] = ((-(ll)(MOD / i) * inv[MOD % i]) % MOD + MOD) % MOD;
}
}
inline void initFi(int k) {
memset(fi, 0, sizeof(fi));
tot = 0;
fi[1] = 1;
for(int i = 2; i <= k + 1; i++) {
if(!fi[i]) {
fi[i] = quickPow(i, k);
prime[tot++] = i;
for(int j = 0; i * prime[j] < N; j++) {
fi[i * prime[j]] = (ll)fi[i] * fi[prime[j]] % MOD;
if(i % prime[j] == 0) {
break;
}
}
}
}
for(int i = 2; i <= k + 1; i++) {
fi[i] = (fi[i] + fi[i - 1]) % MOD;
}
}
inline void Lagrange(ll n, int k) {
int p = 1;
for(int i = 1; i <= k + 1; i++) {
ans[i] = (i + k + 1) & 1 ? MOD - fi[i] : fi[i];
p = (ll)p * ((n - i + 1) % MOD) % MOD * inv[i] % MOD;
ans[i] = (ll)ans[i] * p % MOD;
}
p = 1;
for(int i = k; i >= 1; i--) {
p = (ll)p * ((n - i - 1) % MOD) % MOD * inv[k + 1 - i] % MOD;
ans[i] = (ll)ans[i] * p % MOD;
}
}
int main() {
initInv();
int t;
scanf("%d", &t);
while(t--) {
ll n;
int k;
scanf("%lld%d", &n, &k);
initFi(k);
Lagrange(n, k);
int res = accumulate(ans, ans + k + 2, 0, [] (int a, int b) -> int { return (a + b) % MOD; });
printf("%d\n", res);
}
}