题解 分解

传送门

质数处取值易算
加入质数幂次易算
只要方便加入质数幂次就算不是积性函数也能 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;
}
posted @ 2022-04-11 21:20  Administrator-09  阅读(2)  评论(0编辑  收藏  举报