积性函数
两个互质的整数m,n;
若满足
f
(
n
m
)
=
f
(
n
)
∗
f
(
m
)
f(nm)=f(n)*f(m)
f(nm)=f(n)∗f(m)
这就是一积性函数
两个任意的整数m,n;
若满足
f
(
n
m
)
=
f
(
n
)
∗
f
(
m
)
f(nm)=f(n)*f(m)
f(nm)=f(n)∗f(m)
这就是一完全积性函数
欧拉函数
欧拉函数:在n范围内与n互质的个数
ϕ
(
n
)
=
∑
i
=
1
n
[
g
c
d
(
i
,
n
)
=
1
]
\phi(n)=\sum_{i=1}^n[gcd(i,n)=1]
ϕ(n)=∑i=1n[gcd(i,n)=1]
n
=
p
1
1
∗
p
2
2
.
.
.
∗
p
m
m
n=p_1^1*p_2^2...*p_m^m
n=p11∗p22...∗pmm
所以: ϕ ( n ) = ∑ i = 1 n [ g c d ( i , n ) = 1 ] = n ∗ ( 1 − 1 / p i ) ∗ ( 1 − 1 / p 2 ) . . . ∗ ( 1 − 1 / p m ) \phi(n)=\sum_{i=1}^n[gcd(i,n)=1]=n*(1-1/p_i)*(1-1/p_2)...*(1-1/p_m) ϕ(n)=∑i=1n[gcd(i,n)=1]=n∗(1−1/pi)∗(1−1/p2)...∗(1−1/pm)
ϕ
(
1
)
=
1
\phi(1)=1
ϕ(1)=1
代码如下:
莫比乌斯函数与欧拉函数
莫比乌斯函数
这,是莫比乌斯函数的定义,这时候有人就要问了:
“兄弟兄弟,这式子太麻烦了,我看不懂啊,能不能换个更加通俗易懂的方法?”
“有的兄弟,有的,像这样的通俗解法还有好几个”
莫比乌斯函数完整定义的通俗表达:
1)μ(1)=1;
2)当n存在平方因子时,μ(n)=0;
3)当n是素数或奇数个不同素数之积时,μ(n)=-1;
4)当n是偶数个不同素数之积时,μ(n)=1。
如何求解莫比乌斯函数 我们根据定义,直接进行质因数分解。碰到平方因子直接返回 0 ,
否则每次碰到质因数乘一个 -1 即可。总体时间复杂度是 O(√n)
但是平常做题经常会用到很多个数的莫比乌斯函数值,那么我们就不能用这种方法求了。我
们知道莫比乌斯函数是积性函数,所以很方便使用线性筛求解莫比乌斯函数
μ
(
1
)
=
1
\mu(1)=1
μ(1)=1
找到一个质数
x
,
则
μ
(
x
)
=
−
1
找到一个质数x,则\mu(x)=-1
找到一个质数x,则μ(x)=−1
对于一个和数
x
,如果有平方因子,
μ
(
x
)
=
0
,
否则利用积性函数性质计算
对于一个和数x,如果有平方因子,\mu(x)=0,否则利用积性函数性质计算
对于一个和数x,如果有平方因子,μ(x)=0,否则利用积性函数性质计算
我们再来把欧拉函数加入进去
1.若 n 是素数,
φ
(
n
)
=
n
−
1
φ(n)=n-1
φ(n)=n−1,这个由定义可知。
2.若 n = pk ,
φ
(
n
)
=
p
k
−
p
k
−
1
φ( n ) = pk - pk-1
φ(n)=pk−pk−1 ,这个在之前已经得出。
3.若 n 是奇数,
φ
(
2
n
)
=
φ
(
n
)
φ( 2n ) = φ( n )
φ(2n)=φ(n),因为 n 和 2 互质,
φ
(
2
)
=
1
φ(2)=1
φ(2)=1,由积性函数的性质可得
4.
∑
d
∣
n
ϕ
(
d
)
=
n
\sum_{d|n}\phi(d)=n
∑d∣nϕ(d)=n
5. 若
p
∣
n
p | n
p∣n 且
p
2
∣
n
p2 | n
p2∣n ,则\
ϕ
(
n
)
=
ϕ
(
n
/
p
)
=
p
\phi(n)=\phi(n/p)=p
ϕ(n)=ϕ(n/p)=p
这时我们就能用以上性质用线性筛筛欧拉函数了
模板代码:
整合后代码:
int cnt=0,prime[N],miu[N],phi[N];
bool vis[N];
void ola(int n){
vis[1]=miu[1]=phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[++cnt]=i;
miu[i]=-1;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0){
miu[i*prime[j]]=0;
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
miu[i*prime[j]]=-miu[i];
phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
例题:
AC代码
注意数据量,别忘开long long!!!
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10;
int cnt=0,prime[N],phi[N];
bool vis[N];
void ola(int n){
vis[1]=phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*phi[prime[j]];
//phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
int f[N];
signed main(){
ola(N);
f[1]=0;
for(int i=2;i<=N;i++){
f[i]=f[i-1]+phi[i];
}
int n;
while(cin>>n&&n!=0){
cout<<f[n]<<"\n";
}
return 0;
}