题目
1.学会线性筛出 d(i):i 约数的个数 以及 dd(i):i 所有约数之和。
学习链接
2.慢慢推式子 需要用到 一个小结论(挺好yy证明的)+反演+积累技巧把(比如dd前缀和可以转化成别的式子进而分块求)
学习链接
第三个式子是反演得到的。最后一个橙点点有一丢丢小错误sigma(q=[1,[n/d]).
我还是自己再次按照上述过程首推一下(由于我的式子太丑啦T_T放在代码后面留着自己看)
#include<cstdio>
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
const int N=5e6+5,mod=1e9+7,inv2=500000004;
int is[N+5],prime[N+5];
int dd[N+5],mud[N+5],low[N+5];//dd[i]:i的约数之和 mud[i]=mu[i]*i
void init()//low[i]=1+p1+p1^2+p1^3+..+p1^e1;(p1为i质因数分解的最小项 e1是分解后p1的指数)
{
mud[1]=1*1,dd[1]=1;int tot=0;
for(int i=2;i<=N;++i)
{
if(!is[i]) prime[++tot]=i,mud[i]=-i,dd[i]=low[i]=i+1;
for(int j=1;j<=tot&&(ll)i*prime[j]<=N;++j)
{
int t=i*prime[j];is[t]=1;
if(i%prime[j]==0)
{
mud[t]=0;//i中含有prime[j],t中prime[j]的指数>=2 所以mu[t]=0,mud[t]=0*t=0;
low[t]=(ll)low[i]*prime[j]%mod+1,low[t]%=mod;//prime[j]的指数增大1
dd[t]=(ll)dd[i]/low[i]*low[t]%mod;//除以原来的最小项然后乘以新的最小项
break;
}
mud[t]=(ll)mud[i]*(-prime[j])%mod;//i含有的质因子都大于prime[j] 首先mu[t]=-mu[i] 然后乘了一个prime[j] 也可以直接按积性函数mu[t]=mu[i]*mu[prime[j]];
low[t]=(prime[j]+1)%mod,dd[t]=(ll)dd[i]*low[t]%mod;//t的最小质因子是prime[j] t的最小项成为prime[j]+1
} //dd[t]就是dd[i]多乘以新的质因子prime[j]的贡献 low[t]=pirme[j]+1
}
for(int i=1;i<=N;++i) mud[i]=((ll)mud[i]+mud[i-1])%mod,dd[i]=((ll)dd[i]+dd[i-1])%mod;
}
map<int,int>ans_mud;
inline int cal(ll l,ll r){//id [l,r]之和
return (l+r)%mod*((r-l+1)%mod)%mod*inv2%mod;
}
inline int f_mud(ll n){//f=mu*d g=id f卷积g=n*e
if(n<=N) return mud[n];
if(ans_mud[n]) return ans_mud[n];
ll res=1ll;//卷积单项的时候n可以提出来 mud*id=e e的前缀和不可以将n提出来 对于每一项n不同 T_T
for(ll l=2,r;l<=n;l=r+1)//这个n不是函数的输入变量n 而是卷积的第n项 所以卷积的前n项和是 1*e(1)+2*e(2)+3*e(3)+...n*e(n)=1
r=n/(n/l),res-=(ll)cal(l,r)*f_mud(n/l)%mod,res%=mod;
return ans_mud[n]=(res+mod)%mod;
}
inline int fenkuai_dd(ll n){//求出dd的前nn项和
if(n<=N) return dd[n];
ll res=0;
for(ll l=1,r;l<=n;l=r+1)
r=n/(n/l),res+=cal(l,r)*((n/l)%mod)%mod,res%=mod;
return (res+mod)%mod;
}
inline int solve(ll n){//[l,r]内n/d相同 整体分块求 前半部分杜教筛[l,r]之间的mud的和 后半部分分块求[1,n/l]之间dd的和
ll res=0;
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);int _dd=fenkuai_dd(n/l);
res+=(ll)(f_mud(r)-f_mud(l-1))%mod*_dd%mod*_dd%mod,res%=mod;
}
return (res+mod)%mod;
}
int main(){
init();ll n;scanf("%lld",&n);
printf("%d\n",solve(n));
}