积性函数
两个互质的整数m,n;
若满足f(nm)=f(n)∗f(m)f(nm)=f(n)*f(m)f(nm)=f(n)∗f(m)
这就是一积性函数
两个任意的整数m,n;
若满足f(nm)=f(n)∗f(m)f(nm)=f(n)*f(m)f(nm)=f(n)∗f(m)
这就是一完全积性函数
欧拉函数
欧拉函数:在n范围内与n互质的个数
ϕ(n)=∑i=1n[gcd(i,n)=1]\phi(n)=\sum_{i=1}^n[gcd(i,n)=1]ϕ(n)=∑i=1n[gcd(i,n)=1]
n=p11∗p22...∗pmmn=p_1^1*p_2^2...*p_m^mn=p11∗p22...∗pmm
所以:ϕ(n)=∑i=1n[gcd(i,n)=1]=n∗(1−1/pi)∗(1−1/p2)...∗(1−1/pm)\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)=pk−pk−1φ( n ) = pk - pk-1φ(n)=pk−pk−1 ,这个在之前已经得出。
3.若 n 是奇数, φ(2n)=φ(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∣np | np∣n 且 p2∣np2 | np2∣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;
}
1238

被折叠的 条评论
为什么被折叠?



