定义除数函数:
σk(n)=∑a|nak
令 d=σ1
题目要求计算:
∑i=1n∑j=1nd(ij)
之前做BZOJ的时候做过一题。
http://blog.csdn.net/zlh_hhhh/article/details/77849859
BZOJ 4176 Lucas的数论
对于
σ0(nm)=∑a|nm1=∑a|n∑b|m[a⊥b]
σ1 也有类似结论:
σ1(nm)=d(nm)=∑a|nma =∑a|n∑b|mbna[a⊥b]
证明类似于Lucas的数论:
d(nm)=∑a|nman=∏k=1rPxkkm=∏k=1rPykk
d(nm)=∑a|nma=∑k=1r∑c∣∣∣nmPxk+ykk∑a|Pxk+ykkac=∑a1∣∣∣Px1+y11∑a2∣∣∣Px2+y22...∑ar∣∣∣Pxr+yrr(∏i=1rai)
对于某个素数的
Pk
∑a∣∣∣Pxk+ykka=∑a|Pxkk∑b|Pykk[a⊥b]Pxkkba
所以:
d(nm)=∑a|n∑b|mnba[a⊥b]
answer=∑i=1n∑j=1n∑a|i∑b|jiba[a⊥b]
记:
f(k)=∑i=1n∑j=1n∑a|i∑b|jiba[gcd(a,b)=k]F(k)=∑k|af(a)
F(k)=∑i≤n,k|in∑j≤n,k|jn∑a|ik∑b|jkiba=k∑i≤n,k|in∑j≤n,k|jn∑a|ik∑b|jkikba=k∑i=1⌊nk⌋∑j=1⌊nk⌋∑a|i∑b|jiba=k∑i=1⌊nk⌋∑j=1⌊nk⌋(∑a|iia)(∑b|jb)=k∑i=1⌊nk⌋∑j=1⌊nk⌋d(i)d(j)=kSd(⌊nk⌋)2
对于某一算术函数
g
, Sg 为:
Sg(n)=∑i=1ng(i)
所以:
answer=f(1)=∑k=1nμ(k)kSd(⌊nk⌋)2
令: h(n)=μ(n)n
我们知道: φ−=h∗I
注:不太明白的,可以查看这个:http://blog.csdn.net/zlh_hhhh/article/details/77857141
所以: h∗I∗φ=h∗N=e
对于 Sd .我么即可可以用杜教筛来算。也可以直接 O(n‾‾√ 分段算。
杜教筛的话:
d(n)=∑a|na
可以看出: d=N∗I
所以: d∗μ=N∗I∗μ=N
O(n‾‾√) 算的话:
∑i=1nd(i)=∑in∑a|ia=∑a=1n∑a|i,i≤na=∑a=1na⌊na⌋=∑L=1mL(SN(⌊nL⌋)−SN(⌊nL+1⌋))−∑i=1⌊nm+1⌋i⌊ni⌋
代码:
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <cmath>
#define MAXN 1000006
using namespace std;
typedef long long LL;
const int P=1e9+7;
int mu[MAXN];
int phi_[MAXN];
int Sp[MAXN];
int Sd[MAXN];
int M[MAXN];//梅藤斯函数
int _Sp[MAXN];
int _Sd[MAXN];
int _M[MAXN];
void init()
{
mu[1]=-1;
for(int i=1;i<MAXN;i++)
{
mu[i]=-mu[i];
for(int j=i<<1;j<MAXN;j+=i) mu[j]+=mu[i];
}
for(int i=1;i<MAXN;i++)
{
M[i]=M[i-1]+mu[i];
phi_[i]=i*mu[i];
Sp[i]=phi_[i]+Sp[i-1];
for(int j=i;j<MAXN;j+=i) Sd[j]+=i;
Sd[i]+=Sd[i-1];
if(Sd[i]>=P)Sd[i]-=P;
if(Sp[i]<0)Sp[i]+=P;
if(Sp[i]>=P)Sp[i]-=P;
if(M[i]>=P)M[i]-=P;
if(M[i]<0)M[i]+=P;
}
}
int Sn(int n)
{
if(n&1)
return (LL)((n+1)>>1)*n%P;
else
return (LL)(n>>1)*(n+1)%P;
}
void clat_d(int n,int d)
{
int ans=0,m=sqrt(n)+1;
for(int L=1;L<m;L++)
{
int f1=n/L,f2=n/(L+1);
if(f1<MAXN)
f1=M[f1];
else
f1=_M[L*d];
if(f2<MAXN)
f2=M[f2];
else
f2=_M[(L+1)*d];
ans+=(LL)Sd[L]*((f1-f2+P)%P)%P;
if(ans>=P)ans-=P;
}
for(int i=n/m;i>1;i--)
{
int u=n/i;
if(u<MAXN)
u=Sd[u];
else
u=_Sd[d*i];
ans+=mu[i]*u;
if(ans<0)ans+=P;
if(ans>=P)ans-=P;
}
_Sd[d]=(Sn(n)-ans+P)%P;
}
void clat_m(int n,int d)
{
int ans=0,m=sqrt(n)+1;
for(int L=1;L<m;L++)
{
int u=n/L-n/(L+1);
ans+=(LL)M[L]*u%P;
if(ans>=P)ans-=P;
}
for(int i=n/m;i>1;i--)
{
int u=n/i;
if(u<MAXN)
ans+=M[u];
else
ans+=_M[i*d];
if(ans>=P)ans-=P;
}
_M[d]=(1-ans+P)%P;
}
void clat_p(int n,int d)
{
int ans=0,m=sqrt(n)+1;
for(int L=1;L<m;L++)
{
ans+=(LL)Sp[L]*((Sn(n/L)-Sn(n/(L+1))+P)%P)%P;
if(ans>=P)ans-=P;
}
for(int i=n/m;i>1;i--)
{
int u=n/i;
if(u<MAXN)
u=Sp[u];
else
u=_Sp[i*d];
ans+=(LL)i*u%P;
if(ans>=P)ans-=P;
}
_Sp[d]=(1-ans+P)%P;
}
void slove_Sd(int n)
{
if(n<MAXN)return ;
for(int i=n/MAXN;i;i--) clat_d(n/i,i);
}
void slove_M(int n)//最先计算
{
if(n<MAXN)return ;
for(int i=n/MAXN;i;i--) clat_m(n/i,i);
}
void slove_Sp(int n)
{
if(n<MAXN)return ;
for(int i=n/MAXN;i;i--) clat_p(n/i,i);
}
int main ()
{
init();
int n;
scanf("%d",&n);
slove_M(n);
slove_Sd(n);
slove_Sp(n);
int m=sqrt(n)+1,ans=0;
for(int L=1;L<m;L++)
{
int f1=n/L,f2=n/(L+1),u=(LL)Sd[L]*Sd[L]%P;
if(f1<MAXN)
f1=Sp[f1];
else
f1=_Sp[L];
if(f2<MAXN)
f2=Sp[f2];
else
f2=_Sp[L+1];
ans+=(LL)u*(f1-f2+P)%P;
if(ans>=P)ans-=P;
if(ans<0)ans+=P;
}
for(int i=n/m;i;i--)
{
int u=n/i;
if(u<MAXN)
u=Sd[u];
else
u=_Sd[i];
u=(LL)u*u%P;
ans+=((LL)phi_[i]*u%P+P)%P;
if(ans>=P)ans-=P;
}
printf("%d\n",ans);
}