欧拉函数的证明以及应用(附POJ例题)


定义

ϕ(x):1xx

欧拉函数公式:若x可以被分解素数分解为 x=ap11ap22...apkk

ϕ(x)=x(11a1)(11a2)...(11ak)


证明

关于这个公式的理解,可以先考虑只有一个素数因子的形式。
x=ap ,则1~x中能被a整除的数分别为 a,2a,3a,...,ap ,共 xa 个,剩下的是不能被a整除的数,自然的就和x互质。因此容易得到 ϕ(x)=xxa=x(11a)

从上面的例子可以看出,a的倍数其实是在1~x之间平均分布的。这样的平均分布适用于任何的数的倍数。

当一个数有多个素数因子的时候,可以利用这些因子的倍数是各自平均分布的性质,依次累乘上 (11p) .相当于筛去了p的倍数。

举个例子:30=2·3·5

1,2,3,4,5,6,7,8,9,10,,28,29,30
共30个数,先乘 (112) 剩下了15个数:
1,3,5,7,9,11,13,15,17,19,21,23,25,27,29
再乘 (113) 筛去了5个,剩下10个数:
1,5,7,11,13,17,19,23,25,29
再乘 (115) 筛去2个,剩下8个数:
1,7,11,13,17,19,23,29

这是因为被筛去的数是平均分布的,则剩下的数中,为另一个素数的倍数也是平均分布的。


性质

  1. (n,m)=1,ϕ(nm)=ϕ(n)ϕ(m)
    这表明了欧拉函数是积性函数。利用上面的欧拉函数公式,把n,m分别素因数分解,即可得其正确。

  2. 当x为素数时, ϕ(x)=x1 ;当x为奇数时, ϕ(2x)=x1 .

  3. 当p为素数时,
    (1). 当 pnp2n ϕ(n)=ϕ(np)(p1)
    (2). 当 pnp2n ϕ(n)=ϕ(np)p
    第一种情况, (np,p)=1 由性质1可得成立;
    第二种情况,利用 ϕ(n)ϕ(np) 展开式相除得到p,也可得成立。

  4. d|nϕ(d)=n
    首先,有 (n,m)=1 时, d|mnϕ(d) 是积性函数,即 d|mnϕ(d)=(d|mϕ(d))(d|nϕ(d)) 可以利用乘法原理想清楚这个式子的正确性。
    其次,考虑单个素因子幂的情况。当 n=pa ,则 d|nϕ(d)=ϕ(1)+ϕ(p)+ϕ(p2)+...+ϕ(pa) =1+(p1)+p(p1)+...pa1(p1) =1+(p1)pa1p1=pa
    则当n被拆分为多个素因子的幂的形式,根据前两条即证。

  5. n>1 时, 1到n中与n互质的整数和为 nϕ(n)2
    与n不互质的整数成对出现,平均值为 n2 ,可证。

应用

POJ 2407

给n,求 ϕ(n)
按照欧拉函数公式分解出所有n的质因子即可计算得到答案。复杂度O( n )

int phi(int n)
{
    int ans = n;
    for(int i = 2;i*i <= n;i++)if(n % i == 0)
    {
        ans -= ans/i;
        while(n % i == 0)
            n /= i;
    }
    if(n != 1)
        ans -= ans/n;
    return ans;
}

POJ 1284

给素数p,求原根,即 ϕ(p1)
关于原根的知识之后再补充。

POJ 2478

给n,求ans[n]。其中ans[n]=ans[n-1]+phi[n],且n的范围比较大,在10的6次以内。则考虑打表解决。
先得到能整除i的最小正整数md[i](一定是个素数),再利用性质3,得到phi[i]

void set()
{
    for(int i = 0;i < N;i++)
        md[i] = i;
    for(int i = 2;i < N;i++)  if(md[i] == i)
    {   //也可以只让2和奇数进来
        for(int j = i;j < N;j += i)  if(md[j] == j)
            md[j] = i;  //只要最小的,不要被覆盖
    }
    for(int i = 2;i < N;i++)
    {
        if(md[i] == i)
            phi[i] = i-1;
        else
        {
            phi[i] = phi[i/md[i]];
            if(i/md[i] % md[i])
                phi[i] *= md[i]-1;
            else
                phi[i] *= md[i];
        }
    }
}

后面这种写法比较简短,也可以根据性质3来理解。

void set()
{
    for(int i = 0;i < N;i++)
        phi[i] = i;
    for(int i = 2;i < N;i += 2)
        phi[i] /= 2;  //质数为2先处理一遍
    for(int i = 3;i < N;i += 2) if(phi[i] == i)
    {  //处理奇因子
        for(int j = i;j < N;j += i)
            phi[j] = phi[j]/i*(i-1);
    }
}

POJ 3090

给n,求ans[i] = ans[i-1] + 2*phi[i]

你可能感兴趣的:(--数学)