bzoj 4805 欧拉函数求和 Posted on 2019-06-08 | Views: 练习了min_25筛.跑得挺快的. 注意将所有数都当成质数时, $f(x)=x-1$ ,但它并不是个完全积性函数. 所以要拆成 $f(x)=1,g(x)=x$ 两个函数分别预处理,然后相减. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899#include<bits/stdc++.h>using namespace std;typedef long long ll;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') fh=-1,jp=getchar(); while (jp>='0'&&jp<='9') out=out*10+jp-'0',jp=getchar(); return out*fh;}const int MAXN=1e5+10;int cnt=0,prime[MAXN],ism[MAXN];ll sumphi[MAXN];void init_prime(int n){ ism[1]=1; for(int i=2;i<=n;++i) { if(!ism[i]) prime[++cnt]=i; for(int j=1;j<=cnt && i*prime[j]<=n;++j) { ism[i*prime[j]]=1; if(i%prime[j]==0) break; } } for(int i=1;i<=cnt;++i) sumphi[i]=sumphi[i-1]+prime[i]-1;}ll calcsum(int x){ return 1LL*(2+x)*(x-1)/2;}int tot=0,w[MAXN],id1[MAXN],id2[MAXN];ll f[MAXN],g[MAXN];int N,sqN;ll S(int n,int j){ if(n<=1 || prime[j]>n) return 0; int id=n; if(id<=sqN) id=id1[id]; else id=id2[N/id]; ll res=g[id]-sumphi[j-1]; for(int k=j;k<=cnt && 1LL*prime[k]*prime[k]<=n;++k) { ll pw1=prime[k],pw2=prime[k]*prime[k]; for(int e=1;pw2<=n;++e) { ll tmp=pw1/prime[k]*(prime[k]-1); tmp*=S(n/pw1,k+1); tmp+=pw2/prime[k]*(prime[k]-1); res+=tmp; pw1*=prime[k],pw2*=prime[k]; } } return res;}int main(){ N=read(); sqN=(sqrt(N)); init_prime(sqN); for(int l=1,r;l<=N;l=r+1) { r=N/(N/l); w[++tot]=N/l; if(N/l<=sqN) id1[N/l]=tot; else id2[N/(N/l)]=tot; } for(int i=1;i<=tot;++i) f[i]=w[i]-1,g[i]=calcsum(w[i]); for(int j=1;j<=cnt;++j) for(int i=1;i<=tot && prime[j]*prime[j]<=w[i];++i) { int k=w[i]/prime[j]; if(k<=sqN) k=id1[k]; else k=id2[N/k]; g[i]-=1LL*(prime[j])*(g[k]-sumphi[j-1]-j+1); f[i]-=f[k]-j+1; } for(int i=1;i<=tot;++i) g[i]-=f[i]; ll ans=S(N,1)+1; cout<<ans<<endl; return 0;}