传送门
先从一道简单题入手 (LCM sum)
求
![\sum_{i=1}^nlcm(i,n) [51nod1238] 最小公倍数之和V3 [杜教筛]_i++](https://file.cfanz.cn/uploads/gif/2022/07/12/8/MA1FE575dJ.gif)
![=n\sum_{d|n}\sum_{i=1}^ni/d[gcd(i,n)=d] [51nod1238] 最小公倍数之和V3 [杜教筛]_分块_02](https://file.cfanz.cn/uploads/gif/2022/07/12/8/Z5Q0X7eb59.gif)
令k=i/d
![=n\sum_{d|n}\sum_{k=1}^{n/d}k[gcd(kd,n)=d] [51nod1238] 最小公倍数之和V3 [杜教筛]_分块_03](https://file.cfanz.cn/uploads/gif/2022/07/12/8/3HWE35Saf1.gif)
gcd里面同除d
![=n\sum_{d|n}\sum_{k=1}^{n/d}k[gcd(k,n/d)=1] [51nod1238] 最小公倍数之和V3 [杜教筛]_分块_04](https://file.cfanz.cn/uploads/gif/2022/07/12/8/bfJ1Vfb1DF.gif)
我们发现枚举到n/d 与 d是等价的
![=n\sum_{d|n}\sum_{k=1}^{d}k[gcd(k,d)=1] [51nod1238] 最小公倍数之和V3 [杜教筛]_i++_05](https://file.cfanz.cn/uploads/gif/2022/07/12/8/4538085eaR.gif)
![=n\sum_{d|n}\varphi(d)d+[d=1]/2 [51nod1238] 最小公倍数之和V3 [杜教筛]_分块_06](https://file.cfanz.cn/uploads/gif/2022/07/12/8/M57898565f.gif)
这道题就可以转化为
![Ans=2\sum_{i=1}^n\sum_{j=1}^ilcm(i,j)-\sum_{i=1}^ni [51nod1238] 最小公倍数之和V3 [杜教筛]_i++_07](https://file.cfanz.cn/uploads/gif/2022/07/12/8/LcdJU0Wba7.gif)
![=\sum_{d=1}^nd\varphi(d)\sum_{i=1}^{n/d}id=\sum_{d=1}^nd^2\varphi(d)\sum_{i=1}^{n/d}i [51nod1238] 最小公倍数之和V3 [杜教筛]_#define_08](https://file.cfanz.cn/uploads/gif/2022/07/12/8/73V9C2b46L.gif)
杜教筛筛第一坨, 然后整除分块
#include<bits/stdc++.h>
#define N 1000050
#define LL long long
#define Mod 1000000007
#define inv2 500000004
#define inv6 166666668
using namespace std;
int prim[N], isp[N], tot, phi[N];
LL val[N],n;
map<LL,LL> F;
void prework(){
phi[1] = val[1] = 1;
for(int i=2;i<=N-50;i++){
if(!isp[i]) prim[++tot] = i, phi[i] = i-1;
for(int j=1;j<=tot;j++){
if(i*prim[j] > N-50) break;
isp[i*prim[j]] = 1;
if(i%prim[j] == 0){
phi[i*prim[j]] = phi[i] * prim[j];
break;
}
phi[i*prim[j]] = phi[i] * (prim[j] - 1);
}
}
for(int i=2;i<=N-50;i++) val[i] = (LL)phi[i] * i % Mod * i % Mod;
for(int i=2;i<=N-50;i++) val[i] = (val[i] + val[i-1]) % Mod;
}
LL Sum(LL x){ x %= Mod; return x * (x+1) % Mod * inv2 % Mod;}
LL calc(LL x){ x %= Mod; return x * (x+1) % Mod * ((x*2+1) % Mod) % Mod * inv6 % Mod;}
LL getf(LL x){
if(x<=N-50) return val[x];
if(F[x]) return F[x];
LL ans = Sum(x); ans = (ans * ans) % Mod;
for(LL l=2,r;l<=x;l=r+1){
LL v = x/l; r = x/v;
ans -= (calc(r) - calc(l-1)) * getf(v) % Mod;
ans = (ans % Mod + Mod) % Mod;
} return F[x] = ans;
}
int main(){
prework(); scanf("%lld",&n); LL ans = 0;
for(LL l=1,r;l<=n;l=r+1){
LL v = n/l; r = n/v;
ans += Sum(v) * (getf(r) - getf(l-1)) % Mod;
ans = (ans % Mod + Mod) % Mod;
} printf("%lld",ans); return 0;
}
