题解:https://blog.youkuaiyun.com/Vectorxj/article/details/79094659
套路推式子,杜教筛,证明复杂度。
感谢NicoDafaGood,不在这里写题解了,式子列出来太长啦,写在本本上。
//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const ll mod=1e9+7;
const int maxn=2e6+7,W=2e6;
ll n,g[maxn],inv6;
char cc;ll ff;
template<typename T>void read(T& aa) {
aa=0;cc=getchar();ff=1;
while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
if(cc=='-') ff=-1,cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
aa*=ff;
}
ll pf(ll x) {return x*x%mod;}
ll qp(ll x,ll k) {
ll rs=1;
while(k) {
if(k&1) rs=rs*x%mod;
k>>=1; x=x*x%mod;
}
return rs;
}
ll mu[maxn],prime[maxn],totp;
bool ok[maxn];
void get_p() {
mu[1]=1;
For(i,2,W) {
if(!ok[i]) {
prime[++totp]=i;
mu[i]=-1;
}
For(j,1,totp) {
if(prime[j]>W/i) break;
ok[i*prime[j]]=1;
if(i%prime[j]) mu[i*prime[j]]=-mu[i];
else {
mu[i*prime[j]]=0;
break;
}
}
}
For(i,1,W) g[i]=((g[i-1]+mu[i]*pf(i))%mod+mod)%mod;
}
inline ll f2(ll x) {return x*(x+1)%mod*(2*x+1)%mod*inv6%mod;}
map<ll,ll> G,H;
ll get_g(ll n) {
if(n<=W) return g[n];
ll p=G[n]; if(p) return p;
ll rs=0,lst=1,now;
for(ll i=2,j;i<=n;i=j+1) {
j=n/(n/i); now=f2(j);
rs+=get_g(n/i)*(now-lst+mod)%mod;
lst=now;
}
rs=(1-rs%mod+mod)%mod;
return G[n]=rs;
}
inline ll get_h(ll n) {
if(H[n]) return H[n];
ll rs=0,lst=0,now;
for(ll i=1,j;i<=n;i=j+1) {
j=n/(n/i);
now=get_g(j);
rs+=(n/i)*(now-lst+mod)%mod;
lst=now;
}
return H[n]=rs%mod;
}
ll get_f(ll n) {
ll rs=0,x;
for(ll i=1,j;i<=n;i=j+1) {
j=n/(n/i); x=n/i;
rs+=pf(((x+1)*x/2)%mod)*(get_h(j)-get_h(i-1)+mod)%mod;
}
return rs%mod;
}
int main() {
read(n);
get_p(); inv6=qp(6,mod-2);
ll x=get_f(n);
printf("%lld\n",(x+n)*qp(2,mod-2)%mod);
return 0;
}