欧拉函数

  题外话:(我只是不知道该放哪才写在这的)

  约数的个数 即求正整数 $n$ 的正约数个数

  对于 $n$ 有唯一分解式 $n=p_1^{a_1} \, p_2^{a_2} \, p_3^{a_3}···p_k^{a_k}$

  而对于任意一个质因子 $p_i$ ,在约数中的指数可以是 $0,1,2,3,...,a_i$ 共 $a_i+1$ 种情况,而且不同的素数因子间相互独立

  所以 $n$ 的正约数个数为 $$f(n)= prod_{i=1}^k (a_i+1)$$

  正题:

  欧拉函数 是小于 $n$ 的正整数中与 $n$ 互质的数的个数,规定 $varphi (1)=1$

  还是这个分解式 $n=p_1^{a_1} \, p_2^{a_2} \, p_3^{a_3}···p_k^{a_k}$

  通式(很好记就不证明了) $$varphi (n)=n prod_{i=1}^k (1- frac{1}{p_i})$$

  于是可以 $O(n)$ 求出欧拉函数

int euler(int n){
    int ans=n;
    for (int i=2;i<=sqrt(n);i++)
        if (n%i==0){
            ans=ans/i*(i-1);
            while(n%i==0) n/=i;
        }
    if(n>1) ans=ans/n*(n-1);
    return ans;
}
View Code

  如果是要求出 $1 sim n$ 所有的欧拉函数值 不需要用上面的方法做 $n$ 次

  可以像下面这样做 时间复杂度 大概线性筛?

void euler_table(){
    phi[1]=1;
    for(int i=2;i<=n;i++)
        if(!phi[i])
            for(int j=i;j<=n;j+=i){
                if(!phi[j]) phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
            }
}
View Code

  这是一道关于欧拉函数的题 仪仗队

  分析:以左下角为坐标原点 观察可知图是对称的 所以可以先分析对称轴下面一侧 即x>y 对于一个学生(x,y) 若x,y互质 则该同学可以被看到 若x,y不互质 则x,y至少有一个非1公因子k 于是(x,y)可以写成(kx',ky') 说明学生(x,y)一定会被学生(x',y')挡住 所以对于横坐标为x的学生 可以被看到的学生有φ(x)个 把所有φ值加起来就是一侧的人数 最后记得对称轴上还有一个

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 50000

int n,ans=0;
int phi[N+5]={0};

void euler(){
    phi[1]=1;
    for(int i=2;i<=n;i++)
        if(!phi[i])
            for(int j=i;j<=n;j+=i){
                if(!phi[j]) phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
            }
}

int main(){
    scanf("%d",&n);
    n--;
    euler();
    for(int i=1;i<=n;i++)
        ans+=phi[i];
    if(!n) printf("0");
    else printf("%d
",2*ans+1);
    
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Pedesis/p/10346183.html