重点:k次幂的前缀和是k+1次多项式
即
1
n
+
2
n
+
.
.
.
+
x
n
1^n+2^n+...+x^n
1n+2n+...+xn
朴素模板
洛谷P4781
已知n个点
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
.
.
.
(
x
n
,
y
n
)
(x_1,y_1),(x_2,y_2)...(x_n,y_n)
(x1,y1),(x2,y2)...(xn,yn),求其构成的n-1次多项式中横坐标为k的对应的值。
时间复杂度: O(
n
2
n^2
n2)
// 已知n个点,调用方式(n-1,x,y,k)
// 从0开始
int lagrange(int n, int *x, int *y, int k) {
int ans = 0;
for (int i = 0; i <= n; i++) {
int s1 = 1, s2 = 1;
for (int j = 0; j <= n; j++)
if (i != j) {
s1 = 1ll*s1*(k-x[j])%mod;
s2 = 1ll*s2*(x[i]-x[j])%mod;
}
ans = (1ll*ans+1ll*y[i]*s1%mod*q_pow(s2, mod-2)%mod)%mod;
}
return (ans+mod)%mod;
}
重心拉格朗日
当x连续时,即x=1,2,3…
时间复杂度:O(n)
求阶乘逆元可以套其他模板(本方法可能会慢)
// e个点,可以插出e-1次多项式
ll solve(ll x, int e){
if(x <= e) //直接返回
return a[x];
x %= mo;
ll ans = 0;
pre[0] = suf[e+1] = 1; //边界
for(ll i = 1; i <= e; i++){ //(x-i) 前缀积
pre[i] = pre[i - 1] * (x - i) % mo;
}
for (ll i = e; i >=1 ; i--){ //(x-i) 后缀积
suf[i] = suf[i + 1] * (x - i) % mo;
}
for(ll i = 1; i <= e; i++){
ll f = fac[i - 1] * fac[e - i] % mo; //从 0 到 e时,fac[i-1] 变为 fac[i];
f = (e - i) & 1 ? -f : f; //判断正负
(ans += a[i] * f % mo * pre[i - 1] % mo * suf[i + 1]) %= mo;
}
ans += ans < 0 ? mo : 0;
return ans;
}
int main()
{
for(ll i = 1; i < N; i++){ //预处理逆元
inv[i] = pow(i, mo - 2,mo);
}
fac[0] = 1;
for(int i = 1; i < N; i++){ //预处理阶乘逆元
fac[i] = fac[i - 1] * inv[i] % mo;
}
read(T);
while(T--) {
read(n), read(k);
for(int i=1;i<=k+2;i++) {
b[i] = pow(i,k,mo);
a[i] = (a[i-1] + b[i])%mo;
}
cout << solve(n,k+2) << endl;
}
return 0;
}