0、一些定义
- 定义域为正整数集,陪域为复数域的函数被称为数论函数。
- 设(f(x))是一个数论函数,若对于任意一对互质的正整数(a,b),有(f(ab)=f(a)f(b)),则称(f(x))是积性函数。
- 记(delta(x))为(x)的最小质因子,(gamma(x))为(x)的最大质因子。
- 记(cnt(x))为(x)的质因子个数。
- 记第(i)个质数为(p_i)。特别地,(p_0=1)。
- 记(pi(x))为不超过(x)的质数个数。由素数定理,(pi(x)=O(frac{x}{log x}))。
1、min_25筛
论文题:定义(sigma_0(n))为(n)的正约数个数,求(S(n)=sum_{i=1}^nsigma_0(i^k))。(n,kleq 10^{10})。
拓展:给定一个积性函数(f(x)),且对于任意质数(p)和正整数(e),满足:
- (f(p))是一个关于(p)的低次多项式。
- 计算(f(p^e))的复杂度可忽略。
- 求(S(n)=sum_{i=1}^nf(i))。
解法
令(f(x)=sigma_0(x^k)),容易发现(f(x))是积性函数。
令
[g(n,i)=sum_{substack{2leq xleq n\ delta(x)> p_i}}f(x)
]
那么(S(n)=f(1)+g(n,0))。
考虑计算(g(x))的递推式,将(x)分成质数和合数两个部分,合数部分枚举最小质因子(一定(leq sqrt{n})),质数部分单独计算,于是
[egin{align*} g(n,i)&=sum_{substack{i< jleq pi(sqrt{n})}} sum_{substack{2leq xleq n\ delta(x)=p_j}}f(x)+sum_{i< jleq pi(n)}f(p_j)
\&=sum_{substack{i< jleq pi(sqrt{n})\ p_j^{e+1}leq n,egeq 1}} left(f(p_j^{e+1})+f(p_j^e)sum_{substack{2leq xleq leftlfloorfrac{n}{p_j^e}
ight
floor\ delta(x)> p_j}}f(x)
ight)+sum_{i< jleq pi(n)}f(p_j)
\&=sum_{substack{i< jleq pi(sqrt{n})\ p_j^{e+1}leq n,egeq 1}} left(f(p_j^{e+1})+f(p_j^e)gleft(leftlfloorfrac{n}{p_j^e}
ight
floor,j
ight)
ight)+sum_{1leq jleq pi(n)}f(p_j) -sum_{1leq jleq i}f(p_j)end{align*}]
令
[h(n)=sum_{1leq ileq pi(n)}f(p_i)
]
那么
[g(n,i)=sum_{substack{i< jleq pi(sqrt{n})\ p_j^{e+1}leq n,egeq 1}} left(f(p_j^{e+1})+f(p_j^e)gleft(leftlfloorfrac{n}{p_j^e}
ight
floor,j
ight)
ight)+h(n)-h(p_i)
]
如果能快速计算(h),就可以在很低的复杂度里递推求出(g(n,0))。注意到(f)在质数处的取值为多项式,所以只需要对于非负整数(s),计算(h_s(n)=sum_{1leq ileq pi(n)}p_i^s)。注意到(g(n,i))的递推过程,我们只需要对于(1,2,ldots,lfloorsqrt{n} floor,leftlfloorfrac{n}{lfloorsqrt{n} floor} ight floor,ldots,leftlfloorfrac{n}{2} ight floor,n)这(O(sqrt{n}))个数求出(h)值。
令(h_s'(n,i)),为前(n)个数,经过(i)次埃氏筛后剩下的数的(s)次幂之和。那么(h_s(n)=h_s'(n,pi(sqrt{n})))。
对于计算(h_s'(n,i))的递推式,考虑第(i)轮埃氏筛的过程:
- 若(n<p_i^2),那么不会有任何数被筛去,于是(h_s'(n,i)=h_s'(n,i-1))。
- 若(ngeq p_i^2),那么被筛去的数必有质因子(p_i),于是应当减去(p_i^sh_s'left(leftlfloorfrac{n}{p_i} ight floor,i-1 ight))。但是会有最小质因子小于(p_i)的数被减去,所以应当加上这部分的贡献,为(p_i^sh_s'(p_{i-1},i-1))。
那么
[h_s'(n,i)=h_s'(n,i-1)-[ngeq p_i^2]p_i^sleft(h_s'left(leftlfloorfrac{n}{p_i}
ight
floor,i-1
ight)-h_s'(p_{i-1},i-1)
ight)
]
边界条件为
[h_s'(n,0)=sum_{i=2}^ni^s
]
暴力实现即可。
时间复杂度
(O(frac{n^frac{3}{4}}{log n}))
证明咕着。
例题
注意(f)在质数(p)上的取值为(p^2-p),于是需要同时求出质数的和和平方和,即(h_1,h_2)。然后照着公式实现即可。
#include<cstdio>
#define ll long long
#define P 1000000007
#define inv3 333333336
#define N 200005
ll n;
int prm[N],_prm;
bool vis[N];
inline void sieve(int x){
for(int i=2;i<=x;i++){
if(!vis[i])
prm[++_prm]=i;
for(int j=1;j<=_prm&&i*prm[j]<=x;j++){
vis[i*prm[j]]=1;
if(!(i%prm[j]))
break;
}
}
}
int sq,m;
inline int id(ll x){
return x<=sq?x:m-n/x+1;
}
ll num[N];
int h1[N],h2[N];//h(x)=h2(x)-h1(x),h1,h2开成滚动数组
inline void get_h(){
while(1ll*sq*sq<=n)
sq++;
sq--;
sieve(sq);
for(int i=1;i<=sq;i++)
num[++m]=i;
for(int i=sq;i;i--)
if(n/i>sq)
num[++m]=n/i;
for(int i=1;i<=m;i++){
int tmp=num[i]%P;
h1[i]=1ll*tmp*(tmp+1)/2%P-1;
h2[i]=1ll*tmp*(tmp+1)/2%P*(2*tmp+1)%P*inv3%P-1;
}//边界条件
for(int i=1;i<=_prm;i++)
for(int j=m;num[j]>=1ll*prm[i]*prm[i];j--){//注意倒序递推
int k=id(num[j]/prm[i]);
h1[j]=(h1[j]-1ll*prm[i]*(h1[k]-h1[prm[i-1]]+P)%P+P)%P;
h2[j]=(h2[j]-1ll*prm[i]*prm[i]%P*(h2[k]-h2[prm[i-1]]+P)%P+P)%P;
}
}
inline int g(ll x,int i){
int k=id(x),res=((h2[k]-h1[k]+P)%P-(h2[prm[i]]-h1[prm[i]]+P)%P+P)%P;//h(x)-h(p_i)
for(int j=i+1;j<=_prm&&1ll*prm[j]*prm[j]<=x;j++)
for(ll pe=prm[j];pe*prm[j]<=x;pe=pe*prm[j]){
int tmp=pe%P;
res=(res+1ll*tmp*(tmp-1)%P*g(x/pe,j)%P)%P;//f(p_j^e)*g(x/p_j^e,j)
res=(res+1ll*tmp*prm[j]%P*(1ll*tmp*prm[j]%P-1)%P)%P;//f(p_j^(e+1))
}
return res;
}
int main(){
scanf("%lld",&n);
get_h();
printf("%d
",((g(n,0))+1)%P);
}