[LOJ124] 除數函式求和 1 - 線性篩
阿新 • • 發佈:2020-09-17
Description
給定 \(n \le 10^7,k\),求 \(\sum_{i=1}^n \sigma_k (i)\),其中 \(\sigma_k(n)=\sum_{d|n} d^k\)。
Solution
自然想到交換求和順序,即
\[\sum_{i=1}^n \sigma_k(i) =\sum_{i=1}^n \sum_{d|i} d^k=\sum_{i=1}^n[\frac n i]i^k \]
於是,不妨設 \(f(i)=i^k\),則我們可以對每個 \(f(i)\) 在 \(O(\log n)\) 時間內計算,故總時間複雜度為 \(O(n\log n)\)。由於評測機很快,這樣已經能卡過去了。
考慮到 \(f(i)\) 是完全積性的,我們可以分出 \(i\) 對最小素因子 \(p_i\),利用線性篩計算所有合數的 \(f(i)\)。這樣複雜度為 \(O(n+\frac n {\log n} \log n)=O(n)\),可以接受。
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 10000005; const int mod = 1e9+7; int isp[N],vp[N],f[N],pcnt,n,k,ans; int qpow(int p,int q) { return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod; } signed main() { ios::sync_with_stdio(false); cin>>n>>k; for(int i=2;i<=n;i++) { isp[i]=1; } for(int i=2;i<=n;i++) { if(isp[i]) { vp[++pcnt]=i; f[i]=qpow(i,k); } for(int j=1;j<=pcnt&&vp[j]*i<=n;j++) { isp[i*vp[j]]=0; f[i*vp[j]]=f[i]*f[vp[j]]%mod; if(i%vp[j]==0) break; } } for(int i=1;i<=n;i++) { ans=(ans+(n/i)*f[i]%mod)%mod; } cout<<(ans+n)%mod<<endl; //system("pause"); }