Luogu P5325 【模板】Min_25筛
\[f(p)=p^2-p
\]
对于质数可以分开求
然后min25板子
#include<bits/stdc++.h>
#define ll long long
const int p=1e9+7,inv2=500000004,inv3=333333336;
using namespace std;
const int N=1e6+5;
ll n,w[N];
bool fl[N];
int s,cnt,pri[N],s1[N],s2[N],id1[N],id2[N],g1[N],g2[N];
int mo(int x) {
return x>=p?x-p:x;
}
void init() {
s=sqrt(n);
for(int i=2;i<=s;i++) {
if(!fl[i]) {
pri[++cnt]=i;
s1[cnt]=(s1[cnt-1]+(ll)i*i)%p;
s2[cnt]=mo(s2[cnt-1]+i);
}
for(int j=1;j<=cnt&&(ll)pri[j]*i<=s;j++) {
fl[pri[j]*i]=1;
if(i%pri[j]==0) break;
}
}
int num=0;
for(ll i=1,r;i<=n;i=r+1) {
ll t=n/i; r=n/t; w[++num]=t;
if(t<=s) id1[t]=num;
else id2[n/t]=num;
t%=p;
g1[num]=(t*(t+1)%p*inv2%p*(t+t+1)%p*inv3-1+p)%p;
g2[num]=(t*(t+1)%p*inv2-1+p)%p;
}
for(int j=1;j<=cnt;j++) {
for(int i=1;i<=num&&(ll)pri[j]*pri[j]<=w[i];i++) {
int k=(w[i]/pri[j]<=s?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])]);
g1[i]=mo((g1[i]-(ll)pri[j]*pri[j]%p*(g1[k]-s1[j-1]))%p+p);
g2[i]=mo((g2[i]-(ll)pri[j]*(g2[k]-s2[j-1]))%p+p);
}
}
}
int S(ll u,int j) {
if(u<=1||u<pri[j]) return 0;
int k=(u<=s?id1[u]:id2[n/u]);
int ret=((ll)g1[k]-g2[k]-s1[j-1]+s2[j-1]+p+p)%p;
for(int i=j;i<=cnt&&(ll)pri[i]*pri[i]<=u;i++) {
ll t=pri[i];
for(int e=1;t<=u;e++,t*=pri[i]) {
ret=(ret+(ll)(S(u/t,i+1)+(e!=1))*(t%p)%p*((t-1)%p))%p;
}
}
return ret;
}
int main() {
scanf("%lld",&n);
init();
printf("%d\n",mo(1+S(n,1)));
return 0;
}