Description:
求 $ sum_{i=1}^n phi(i) ,sum_{i=1}^n mu(i)$
Hint:
(n<=10^{10})
Solution:
考虑积性函数 (f,g,h) 及其前缀和 (F,G,H)
其中 (h=f*g)
首先 (H(x)=sum_{n=1}^xh(n))
(=sum_{n=1}^x sum_{d|n} f(d) g(frac{n}{d}))
枚举倍数转枚举因数
(=sum_{k=1}^x sum_{d=1}^{lfloor frac{x}{k} floor} f(d) g(k))
$=sum_{k=1}^x g(k)sum_{d=1}^{lfloor frac{x}{k} floor} f(d) $
(=sum_{k=1}^x g(k) F(lfloor frac{x}{k} floor))
(=sum_{k=1}^{x}g(k)F(lfloor frac{x}{k} floor))
故 (g(1)F(n)=H(n)-sum_{d=2}^{n}g(d)F(lfloor frac{n}{d} floor))
此式是杜教筛的核心式,适用于非线性求一个积性函数的前缀和
只要能快速求出 (H(n),sum g(d)) 就能在$ O(n^{ frac{2}{3}} ) $ 求出(F(n))
故
(sum_{i=1}^n phi(i)=frac{n(n+1)}{2}-sum_{i=2}^n phi(lfloor frac{n}{i} floor))
(sum_{i=1}^n mu(i)=1-sum_{i=2}^n mu(lfloor frac{n}{i} floor))
先筛出线性数据范围内的,再杜教筛
递归求解即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mxn=5e6+5,inf=2147483647;
int T,n,tot;
int p[mxn],vis[mxn];
ll mu[mxn],ph[mxn];
map<int ,ll > smu,sph;
void init()
{
vis[1]=mu[1]=ph[1]=1;
for(int i=2;i<=mxn;++i) {
if(!vis[i]) mu[i]=-1,ph[i]=i-1,p[++tot]=i;
for(int j=1;j<=tot&&p[j]*i<=mxn;++j) {
vis[p[j]*i]=1;
if(i%p[j]) mu[p[j]*i]=-mu[i],ph[p[j]*i]=ph[p[j]]*ph[i];
else {ph[p[j]*i]=ph[i]*p[j];break;}
}
}
for(int i=2;i<=mxn;++i) mu[i]+=mu[i-1],ph[i]+=ph[i-1];
}
ll get_mu(int n)
{
if(n<=mxn) return mu[n];
if(smu[n]) return smu[n]; ll ans=0;
for(int l=2,r;r<inf&&l<=n;l=r+1)
r=n/(n/l),ans+=(r-l+1)*get_mu(n/l);
return smu[n]=1ll-ans;
}
ll get_ph(int n)
{
if(n<=mxn) return ph[n];
if(sph[n]) return sph[n]; ll ans=0;
for(int l=2,r;r<inf&&l<=n;l=r+1) //一定是从2开始
r=n/(n/l),ans+=(r-l+1)*get_ph(n/l);
return sph[n]=(ull)n*(n+1ll)/2-ans;
}
int main()
{
cin>>T; init();
while(T--) {
scanf("%d",&n);
printf("%lld %lld
",get_ph(n),get_mu(n));
}
return 0;
}