除数函数求和 1(分块+欧拉筛)
输入格式
第一行两个正整数 。
输出格式
第一行输出答案。
样例
输入样例
5 2
输出样例
63
该题目式一个数论分块加筛法,当然快速幂加数论分块也能过
就是考虑n的一个因子的d在整个函数中的贡献是多少。
套上数论分块的思想,一个因子d对式子的贡献是⌊n/d⌋×d^k。
这样我们需要处理的就是d^k,直接O(nlogk)快速幂求出每个因子的幂是肯定不行的,因为n是1e7,直接会T。
那么还是考虑优化,我们发现,每个数都能唯一分解,而在求幂时会有重复计算的质因子幂。于是,我们考虑线筛,这样就可以用每个数的最小质因子幂去算它的幂了,那么整个过程只会对n≤1e7完全可行。类死于欧拉函数,因为a^k*b^k==(a*b)^k
所以最后就只需再O(n)扫一遍因子累加贡献求和就好了。
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1e7+100; const int mod=1e9+7; ll n,k; int cnt=0; ll sum[maxn]; ll prime[maxn]; bool biaoji[maxn]; ll qpow(ll a,ll b){ ll ans=1; while(b){ if(b&1){ ans=(ans*a)%mod; } a=(a*a)%mod; b/=2; } return ans%mod; } void inint(){ sum[1]=1; //重要 for(int i=2;i<=n+2;i++){ if(!biaoji[i]){ prime[++cnt]=i; sum[i]=qpow(i,k)%mod; } for(int j=1;j<=cnt&&i*prime[j]<=n+2;j++){ biaoji[i*prime[j]]=1; sum[i*prime[j]]=(1ll*sum[i]*sum[prime[j]])%mod; if(i%prime[j]==0){ break; } } } } int main(){ cin>>n>>k; inint(); ll ans=0; for(int i=1;i<=n;i++){ ans=(ans+((n/i)*sum[i])%mod)%mod; } printf("%lld\n",ans); }