当前位置 : 主页 > 编程语言 > java >

杜教筛 [理解+模板]

来源:互联网 收集:自由互联 发布时间:2022-07-07
​​传送门​​ 杜教筛解决这类问题: 求 其中 我们寻找一个函数 g, 看能不能求出 看看我们要什么 (g为积性函数 - g(1) = 1) 于是要求的变成 我们选出g 使第一个很好求, 然后第二个可以整

​​传送门​​

杜教筛解决这类问题: 

求      杜教筛 [理解+模板]_i++      其中  杜教筛 [理解+模板]_#define_02

 

杜教筛 [理解+模板]_i++_04

看看我们要什么 (g为积性函数 -> g(1) = 1)

杜教筛 [理解+模板]_i++_05

 于是要求的变成

杜教筛 [理解+模板]_i++_06

我们选出g 使第一个很好求, 然后第二个可以整除分块递归下去


本题的解决方案

 

当 f 为 mu 时, 考虑

杜教筛 [理解+模板]_#define_07

令g = I, 那么

杜教筛 [理解+模板]_#define_08

 

当 f 为 phi 时, 考虑

杜教筛 [理解+模板]_预处理_09

令 g = I

杜教筛 [理解+模板]_i++_10


时间复杂度的分析

杜教筛 [理解+模板]_预处理_11

然后可以线性筛预处理<=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;
}

 


上一篇:Mysql如何使用帮助
下一篇:没有了
网友评论