传送门 杜教筛解决这类问题: 求 其中 我们寻找一个函数 g, 看能不能求出 看看我们要什么 (g为积性函数 - g(1) = 1) 于是要求的变成 我们选出g 使第一个很好求, 然后第二个可以整
传送门
杜教筛解决这类问题:
求
其中 ![n </p><p>我们寻找一个函数 g, 看能不能求出</p><p><img src='http://img.558idc.com/uploadfile/allimg/java/05094906_62c3989220d661010.gif' alt='杜教筛 [理解+模板]_#define_03' title= 杜教筛 [理解+模板]_#define_02](http://img.558idc.com/uploadfile/allimg/java/05094905_62c398918fae960268.gif)
![杜教筛 [理解+模板]_i++_04](https://s2.51cto.com/images/blog/202207/05094906_62c3989220d661010.gif%3D%5Csum%20_%7Bi%3D1%7D%5En%5Csum_%7Bd%7Ci%7Df%28i/d%29g%28d%29%3D%5Csum_%7Bd%3D1%7D%5Eng%28d%29%5Csum_%7Bi%3D1%7D%5E%7Bn/d%7Df%28i%29%3D%5Csum_%7Bd%3D1%7D%5Eng%28d%29S%5Bn/d%5D?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
看看我们要什么 (g为积性函数 -> g(1) = 1)
![g(1)S(n) 杜教筛 [理解+模板]_i++_05](http://img.558idc.com/uploadfile/allimg/java/05094907_62c3989369e6699252.gif)
于是要求的变成
![杜教筛 [理解+模板]_i++_06](https://s2.51cto.com/images/blog/202207/05094907_62c3989369e6699252.gif%3D%5Csum%20_%7Bi%3D1%7D%5Eng%28i%29S%5Bn/i%5D-%5Csum%20_%7Bi%3D2%7D%5Eng%28i%29S%5Bn/i%5D%3D%5Csum_%7Bi%3D1%7D%5En%28f*g%29%28i%29-%5Csum%20_%7Bi%3D2%7D%5Eng%28i%29S%5Bn/i%5D?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
我们选出g 使第一个很好求, 然后第二个可以整除分块递归下去
本题的解决方案
当 f 为 mu 时, 考虑
![\mu*I=e 杜教筛 [理解+模板]_#define_07](http://img.558idc.com/uploadfile/allimg/java/05094908_62c398947dc556192.gif)
令g = I, 那么
![S(n)=1-\sum _{i=2}^nS[n/i] 杜教筛 [理解+模板]_#define_08](http://img.558idc.com/uploadfile/allimg/java/05094909_62c39895373d993182.gif)
当 f 为 phi 时, 考虑
![\varphi*I=Id 杜教筛 [理解+模板]_预处理_09](http://img.558idc.com/uploadfile/allimg/java/05094909_62c39895e350d30150.gif)
令 g = I
![S(n)=\sum _{i=1}^n Id(i)-\sum _{i=2}^nS[n/i] = n*(n+1)/2 - \sum _{i=2}^nS[n/i] 杜教筛 [理解+模板]_i++_10](http://img.558idc.com/uploadfile/allimg/java/05094911_62c398974d58045370.gif)
时间复杂度的分析
![杜教筛 [理解+模板]_预处理_11](http://img.558idc.com/uploadfile/allimg/java/05094911_62c39897ce26d92473.png)
然后可以线性筛预处理<=m 的值, 反正空间开得下就尽量多处理一些就可以了
#include<bits/stdc++.h>
#define N 5000050
#define LL long long
using namespace std;
int T;
int prim[N],isp[N],tot;
int mu[N]; LL phi[N];
map<int,int> Mu;
map<int,LL> Phi;
void prework(){
mu[1] = phi[1] = 1;
for(int i=2;i<=N-50;i++){
if(!isp[i]) prim[++tot] = i, mu[i] = -1, phi[i] = i-1;
for(int j=1;j<=tot;j++){
if(i * prim[j] > N -50) break;
isp[i * prim[j]] = 1;
if(i % prim[j] == 0){
mu[i * prim[j]] = 0;
phi[i * prim[j]] = phi[i] * (LL)prim[j];
break;
}
else{
mu[i * prim[j]] = -mu[i];
phi[i * prim[j]] = phi[i] * (LL)(prim[j] - 1);
}
}
}
for(int i=2;i<=N-50;i++) mu[i] += mu[i-1], phi[i] += phi[i-1];
}
LL get_Phi(int x){
if(x<=N-50) return phi[x];
if(Phi[x]) return Phi[x];
LL ans = (LL)x * (LL)(x+1) / 2;
for(int l=2,r;l<=x;l=r+1){
int val = x/l; r = x/val;
ans -= (LL)(r-l+1) * get_Phi(val);
} return Phi[x] = ans;
}
int get_Mu(int x){
if(x<=N-50) return mu[x];
if(Mu[x]) return Mu[x];
int ans = 1;
for(int l=2,r;l<=x;l=r+1){
int val = x/l; r = x/val;
ans -= (r-l+1) * get_Mu(val);
} return Mu[x] = ans;
}
int main(){
prework(); scanf("%d",&T);
while(T--){
int n; scanf("%d",&n);
printf("%lld %d\n", get_Phi(n), get_Mu(n));
} return 0;
}
