卧薪尝胆,厚积薄发。
自然数幂和
Date: Fri Nov 30 11:07:37 CST 2018
In Category:
总结
问题:
求从
$1$
到
$N$
的
$K$
次方和,即:
$$
\sum_{i=1}^ni^k
$$
1、线性筛法
首先
$id^k(x)$
是一个完全积性函数,所以可以线性筛,然后再求一个前缀和。
时间复杂度:
$O(n\log k/\ln n+n)$
不需要逆元。
2、递推差分表法
$$
(n+1)^{k+1}-n^{k+1}=C_{k+1}^kn^k+C_{k+1}^{k-1}n^{k-1}++\cdots+C_{k+1}^1n^1+C_{k+1}^0n^0
$$
累加得到:
$$
(n+1)^{k+1}-1=C_{k+1}^1\sum_{i=1}^ni^k+C_{k+1}^2\sum_{i=1}^ni^{k-1}+\cdots+C_{k+1}^k\sum_{i=1}^ni+n
$$
移项再做一次除法:
$$
\sum_{i=1}^ni^k=\frac{1}{k+1}[(n+1)^{k+1}-(C_{k+1}^2\sum_{i=1}^ni^{k-1}+\cdots+C_{k+1}^k\sum_{i=1}^ni+n+1)]
$$
设:
$$
S(n,k)=\sum_{i=1}^ni^k
$$
那么有递推式:
$$
S(n,k)=\frac1{k+1}[(n+1)^{k+1}-(C_{k+1}^2S(n,k-1)+\cdots+C_{k+1}^kS(n,1)+n+1)]
$$
这样递推就可以了。
时间复杂度
$O(k^2)$
。
需要逆元。
时间复杂度不是很优秀。
3、拉格朗日插值法
观察差分表法的式子,我们发现
$S(n,k)$
一定可以表示为一个
$n$
的
$k+1$
次多项式,共
$k+2$
项。
那我们如果构造出了这个多项式,就可以把
$n$
代入求和。
考虑不经过差分表法的转化,直接用拉格朗日插值把原多项式插出来。
设
$\begin{align}f(n)=\sum_{i=1}^ni^k\end{align}$
$$
f(n)=\sum_{i=0}^{k+1}f(i)\times \frac{\begin{align}\prod_{j=0,i\ne j}^{k+1}(n-j)\end{align}}{\begin{align}\prod_{j=0,j\ne i}^{k+1}(i-j)\end{align}}
=\sum_{i=0}^{k+1}f(i)\times \frac{n!/(n-i)!\times(n-i-1)!/(n-k-2)!}{i!/(k+1-i)!\times(-1)^{k+1-i}}
$$
于是
$f(i),i\in[0,k+1]$
可以暴力求,或者线性筛也可以,但是快速幂常数小,后面那个东西维护一下连乘积还有阶乘的逆元就可以了。
时间复杂度
$O(n+k)$
。
需要逆元。
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
typedef long long ll;
ll L,R,k;
#define MAXK 1000010
ll pows[MAXK];
ll fac[MAXK],inv[MAXK];
#define MOD 998244353
ll power(ll a,ll b)
{
ll res = 1;
while(b > 0)
{
if(b & 1)res = res * a % MOD;
a = a * a % MOD;
b = b >> 1;
}
return res;
}
ll p[MAXK];
ll lagrange(ll n)
{
ll ans = 0;
if(n <= k + 1)ans = pows[n];
else
{
p[0] = n;
for(ll i = 1;i <= k + 1;++i)
{
p[i] = p[i - 1] * (n - i) % MOD;
}
for(ll i = 0;i <= k + 1;++i)
{
ll res = pows[i];
res = res * p[k + 1] % MOD;
res = res * power(n - i,MOD - 2) % MOD;
res = res * inv[i] % MOD;
res = res * inv[k + 1 - i] % MOD;
ans = ((ans + res * (((i + k) & 1) ? 1 : MOD - 1)) % MOD + MOD) % MOD;
}
}
return ans;
}
int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%lld%lld%lld",&L,&R,&k);
for(ll i = 1;i < MAXK;++i)pows[i] = power(i,k);
for(ll i = 1;i < MAXK;++i)pows[i] = (pows[i] + pows[i - 1]) % MOD;
fac[0] = 1;
for(ll i = 1;i < MAXK;++i)fac[i] = fac[i - 1] * i % MOD;
inv[MAXK - 1] = power(fac[MAXK - 1],MOD - 2);
for(ll i = MAXK - 2;i >= 0;--i)inv[i] = inv[i + 1] * (i + 1) % MOD;
cout << (lagrange(R) - lagrange(L - 1) + MOD) % MOD << endl;
fclose(stdin);
fclose(stdout);
return 0;
}
In tag:
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡