陈老师R老师等式
∑i=1n∑j=1nf(ij)=∑i=1n∑j=1n⌊ni⌋⌊nj⌋[(i,j)=1]
反演一下就变成
∑i=1nμ(i)(∑d=1⌊ni⌋⌊nid⌋)2
后面的东西也分块求,复杂度证明跟杜教筛复杂度证明差不多
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
const int N=10000010,P=1000000007;
int p[N],mu[N];
map<int,int> S;
inline int g(int n){
int ret=0;
for(int i=1,j;i<=n;i=j+1){
j=n/(n/i);
ret=(ret+1LL*(j-i+1)*(n/i))%P;
}
return 1LL*ret*ret%P;
}
int Sum(int n){
if(n<=1000000) return mu[n];
if(S.count(n)) return S[n];
int ret=1;
for(int i=2,j;i<=n;i=j+1){
j=n/(n/i);
ret=(ret-1LL*(j-i+1)*Sum(n/i))%P;
}
return S[n]=ret;
}
int n;
inline void Pre(){
mu[1]=1;
for(int i=2;i<=1000000 && i<=n;i++){
if(!p[i]) p[++*p]=i,mu[i]=-1;
for(int j=1;j<=*p && 1LL*i*p[j]<=1000000 && 1LL*i*p[j]<=n;j++){
p[i*p[j]]=1;
if(i%p[j]) mu[i*p[j]]=-mu[i];
else break;
}
}
for(int i=1;i<=1000000 && i<=n;i++)
mu[i]=(mu[i]+mu[i-1])%P;
}
int main(){
int ans=0; scanf("%d",&n); Pre();
for(int i=1,j,lst=0;i<=n;i=j+1){
j=n/(n/i); int cur=Sum(j);
ans=(ans+1LL*(cur-lst)*g(n/i))%P;
lst=cur;
}
printf("%d\n",(ans+P)%P);
return 0;
}