BZOJ 3944: Sum
记F[n]为f[i]的前缀和,G[n]为g[i]的前缀和。若g[i]=∑d|n f[i],有F[n]=G[n]-∑F[n/i](i=2...n)
然后存下n^(2/3)的F[i]开个map然后记忆化搜索一下就好了。
若f[i]=φ[i],G[n]=n(n+1)/2,若f[i]=μ[i],G[n]=1
#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> #include<map> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 4000001 #define mm 1000000007 using namespace std; typedef long long ll; ll a[maxn],phi[maxn],mo[maxn],mx; int n,pri[maxn/5],b[maxn],tot; map<int,ll> mp,mp2; ll read(){ ll x=0,f=1; char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();} return x*f; } void init() { int n=mx; clr(b,0); mo[1]=1; phi[1]=1; rep(i,2,n) { if (!b[i]) pri[++tot]=i,b[i]=1,phi[i]=i-1,mo[i]=-1; rep(j,1,tot){ if (pri[j]*i>mx) break; b[i*pri[j]]=1; if (i%pri[j]!=0) phi[i*pri[j]]=phi[i]*(pri[j]-1),mo[i*pri[j]]=-mo[i]; else { phi[i*pri[j]]=phi[i]*pri[j]; mo[i*pri[j]]=0; break; } } } rep(i,1,n) phi[i]+=phi[i-1]; rep(i,1,n) mo[i]+=mo[i-1]; } ll dfs(ll n){ if (n<=mx) return phi[n]; if (mp.count(n)) return mp[n]; ll x; x=n*(n+1)/2; for (ll i=2,pos;i<=n;i=pos+1){ pos=n/(n/i); x-=dfs(n/i)*(pos-i+1); } return mp[n]=x; } ll dfs2(ll n){ if (n<=mx) return mo[n]; if (mp2.count(n)) return mp2[n]; ll x=1; for (ll i=2,pos;i<=n;i=pos+1){ pos=n/(n/i); x-=dfs2(n/i)*(pos-i+1); } return mp2[n]=x; } int main(){ n=read(); mx=4000000; init(); rep(i,1,n){ ll x=read(); printf("%lld %lld\n",dfs(x),dfs2(x)); } return 0; }