除数函数求和 1(分块+欧拉筛)

 

 

 

输入格式

第一行两个正整数  。

输出格式

第一行输出答案。

样例

输入样例

5 2

输出样例

63

参考博客

 

该题目式一个数论分块加筛法,当然快速幂加数论分块也能过

就是考虑n的一个因子d在整个函数中的贡献是多少。

套上数论分块的思想,一个因子d对式子的贡献是n/d×d^k

这样我们需要处理的就是d^k,直接O(nlogk)快速幂求出每个因子的幂是肯定不行的,因为n1e7,直接会T。

那么还是考虑优化,我们发现,每个数都能唯一分解,而在求幂时会有重复计算的质因子幂。于是,我们考虑线筛,这样就可以用每个数的最小质因子幂去算它的幂了,那么整个过程只会对n1e7完全可行。类死于欧拉函数,因为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);
} 

 

 

 

 

posted @ 2020-10-25 10:20  哎呦哎(iui)  阅读(147)  评论(0编辑  收藏  举报