题解 分解
质数处取值易算
加入质数幂次易算
只要方便加入质数幂次就算不是积性函数也能 min25 筛
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec second
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
ll n;
const ll mod=1e9+7, inv2=(mod+1)>>1;
// namespace force{
// bool npri[N];
// ll w[N], ans;
// int sta[N], pre[N], suf[N], top;
// int pri[N], low[N], lowp[N], phi[N], sgm[N], pcnt;
// void solve() {
// for (int i=2; i<=n; ++i) {
// if (!npri[i]) pri[++pcnt]=low[i]=lowp[i]=i, phi[i]=i-1, sgm[i]=i+1;
// for (int j=1,x; j<=pcnt&&i*pri[j]<=n; ++j) {
// npri[x=i*pri[j]]=1;
// if (!(i%pri[j])) {
// phi[x]=phi[i]*pri[j];
// if (i==low[i]) sgm[x]=sgm[i]*pri[j]+1;
// else sgm[x]=sgm[i/low[i]]*sgm[low[i]*pri[j]];
// low[x]=low[i]*pri[j]; lowp[x]=pri[j];
// break;
// }
// else phi[x]=phi[i]*phi[pri[j]], sgm[x]=sgm[i]*sgm[pri[j]], low[x]=lowp[x]=pri[j];
// }
// }
// w[1]=1;
// for (int i=2; i<=n; ++i) {
// top=0;
// for (int t=i; t>1; t/=low[t]) sta[++top]=low[t];
// // cout<<"sta: "; for (int j=1; j<=top; ++j) cout<<sta[j]<<' '; cout<<endl;
// pre[0]=suf[top+1]=1;
// for (int j=1; j<=top; ++j) pre[j]=pre[j-1]*phi[sta[j]];
// for (int j=top; j; --j) suf[j]=suf[j+1]*sgm[sta[j]];
// for (int j=1; j<=top; ++j) w[i]=(w[i]+lowp[sta[j]]*pre[j-1]%mod*suf[j+1])%mod;
// }
// for (int i=1; i<=n; ++i) ans=(ans+w[i])%mod;
// // cout<<"i: "; for (int i=1; i<=n; ++i) cout<<setw(2)<<i<<' '; cout<<endl;
// // cout<<"w: "; for (int i=1; i<=n; ++i) cout<<setw(2)<<w[i]<<' '; cout<<endl;
// cout<<(ans%mod+mod)%mod<<endl;
// }
// }
// namespace task1{
// bool npri[N];
// ll w[N], ans;
// int pri[N], low[N], high[N], phi[N], sgm[N], pcnt;
// void solve() {
// for (int i=2; i<=n; ++i) {
// if (!npri[i]) pri[++pcnt]=low[i]=i, phi[i]=i-1, sgm[i]=i+1;
// for (int j=1,x; j<=pcnt&&i*pri[j]<=n; ++j) {
// npri[x=i*pri[j]]=1;
// if (!(i%pri[j])) {
// phi[x]=phi[i]*pri[j];
// if (i==low[i]) sgm[x]=sgm[i]*pri[j]+1;
// else sgm[x]=sgm[i/low[i]]*sgm[low[i]*pri[j]];
// low[x]=low[i]*pri[j];
// break;
// }
// else phi[x]=phi[i]*phi[pri[j]], sgm[x]=sgm[i]*sgm[pri[j]], low[x]=pri[j];
// }
// }
// w[1]=0; phi[1]=1; high[1]=0;
// ll t;
// for (int i=1; i<=n; ++i) {
// for (int j=high[i]+1; j<=pcnt&&1ll*i*pri[j]<=n; ++j) {
// t=1ll*pri[j]*phi[i];
// for (ll k=pri[j],x; (x=i*k)<=n; k*=pri[j]) {
// w[x]=(w[i]*sgm[k]+t)%mod;
// high[x]=j;
// }
// }
// }
// w[1]=1;
// // cout<<"i: "; for (int i=1; i<=n; ++i) cout<<setw(2)<<i<<' '; cout<<endl;
// // cout<<"w: "; for (int i=1; i<=n; ++i) cout<<setw(2)<<w[i]<<' '; cout<<endl;
// for (int i=1; i<=n; ++i) ans=(ans+w[i])%mod;
// cout<<(ans%mod+mod)%mod<<endl;
// }
// }
namespace task{
bool npri[N];
int pri[N], id1[N], id2[N], sqr, tot, pcnt;
ll uni[N], sp0[N], sp1[N], g0[N], g1[N];
pair<ll, ll> f(ll m, int k) {
// cout<<"f: "<<m<<' '<<k<<endl;
if (m<pri[k]) return {0, 0};
int id=m<=sqr?id1[m]:id2[n/m];
pair<ll, ll> ans={g1[id]-sp1[k-1], (g1[id]+g0[id]-(sp1[k-1]+sp0[k-1]))%mod};
for (int i=k; i<=pcnt&&1ll*pri[i]*pri[i]<=m; ++i) {
ll phi=pri[i]-1, sgm=pri[i]+1;
for (ll j=pri[i]; j*pri[i]<=m; j*=pri[i],phi=phi*pri[i]%mod,sgm=(sgm*pri[i]+1)%mod) {
int t=m/j<=sqr?id1[m/j]:id2[n/(m/j)];
pair<ll, ll> tem=f(m/j, i+1);
ans.fir=(ans.fir+pri[i]+phi*tem.fir+pri[i]*tem.sec)%mod;
ans.sec=(ans.sec+(sgm*pri[i]+1)+sgm*tem.sec)%mod;
}
}
// cout<<"return: "<<ans.fir<<' '<<ans.sec<<endl;
return ans;
}
void solve() {
sqr=sqrt(n);
for (int i=2; i<=sqr; ++i) {
if (!npri[i]) pri[++pcnt]=i, sp0[pcnt]=sp0[pcnt-1]+1, sp1[pcnt]=(sp1[pcnt-1]+i)%mod;
for (int j=1; j<=pcnt&&i*pri[j]<=sqr; ++j) {
npri[i*pri[j]]=1;
if (!(i%pri[j])) break;
}
}
for (ll l=1,r; l<=n; l=r+1) {
r=n/(n/l);
uni[++tot]=n/l;
if (n/l<=sqr) id1[n/l]=tot;
else id2[n/(n/l)]=tot;
ll t=n/l%mod;
g0[tot]=t-1;
g1[tot]=t*(t+1)%mod*inv2%mod-1;
// for (int i=2; i<=n/l; ++i) if (!npri[i]) {
// ++g0[tot];
// g1[tot]=(g1[tot]+i)%mod;
// }
}
for (int i=1; i<=pcnt; ++i) {
for (int j=1; j<=tot&&1ll*pri[i]*pri[i]<=uni[j]; ++j) {
int t=uni[j]/pri[i] <= sqr ? id1[uni[j]/pri[i]] : id2[n/(uni[j]/pri[i])];
g0[j]=(g0[j]-1ll*(g0[t]-sp0[i-1]))%mod;
g1[j]=(g1[j]-pri[i]*(g1[t]-sp1[i-1]))%mod;
}
}
// cout<<"g0: "; for (int i=1; i<=tot; ++i) cout<<g0[i]<<' '; cout<<endl;
// cout<<"g1: "; for (int i=1; i<=tot; ++i) cout<<g1[i]<<' '; cout<<endl;
printf("%lld\n", ((f(n, 1).fir+1)%mod+mod)%mod);
// cout<<f(n, 1).sec<<endl;
}
}
signed main()
{
freopen("b.in", "r", stdin);
freopen("b.out", "w", stdout);
n=read();
// cout<<double(sizeof(task1::pri)*3+sizeof(task1::npri))/1000/1000<<endl;
// force::solve();
// task1::solve();
task::solve();
return 0;
}