【菜鸟er】常见问题_ 欧拉函数

//欧拉函数:小于或等于n的数中与n互质的数的数目
/**
p^k型欧拉函数:
若N是质数p(即N=p), φ(n)= φ(p)=p-p^(k-1)=p-1。
若N是质数p的k次幂(即N=p^k),φ(n)=p^k-p^(k-1)=(p-1)p^(k-1)。

mn型欧拉函数
设n为正整数,以φ(n)表示不超过n且与n互素的正整数的个数,称为n的欧拉函数值。
若m,n互质,φ(mn)=(m-1)(n-1)=φ(m)φ(n)。

特殊性质:
若n为奇数时,φ(2n)=φ(n)。
对于任何两个互质 的正整数a,n(n>2)有:a^φ(n)=1 mod n (恒等于)此公式即 欧拉定理
当n=p 且 a与素数p互质(即:gcd(a,p)=1)则上式有: a^(p-1)=1 mod n (恒等于)此公式即 费马小定理

1-12与12的最大公约数和就为
φ(1)*12+φ(2)*6+φ(3)*4+φ(4)*3+φ(6)*2+φ(12)*1

完全余数集合:
定义小于 n 且和 n 互质的数构成的集合为 Z(n) ,称呼这个集合为 n 的完全余数集合。 显然 |Z(n)| =φ(n) 。
同余定理:
     如果 a mod b = c 则有(a+kb) mod b =c(k为非0整数)
     如果 a mod b = c 则有(ka) mod b =kc (k为正整数)
     (a+b) mod c =((a mod c)+(b mod c )) mod c;
     (a*b) mod c=((a mod c)*(b mod c)) mod c
*/
#include <bits/stdc++.h>
using namespace std;
//直接求
int oula1(int n)
{
    int res=n,a=n;
    for(int i=2;i*i<=a;i++){
       if(a%i==0){
           res=res/i*(i-1);
           while(a%i==0) a/=i;
       }
    }
    if(a>1) res=res/a*(a-1);
    return res;

}
//线性筛法
const int Max=30000;//
int euler[Max] = {0};
int oula2(int n){

    euler[1]=1;
    for(int i=2;i<Max;i++)
    euler[i]=i;
    for(int i=2;i<Max;i++)
    if(euler[i]==i)
       for(int j=i;j<Max;j+=i)
          euler[j]=euler[j]/i*(i-1);

    return euler[n];
}
const int M=50000;//
int prime[M]={0};
int vis[M]={0};
int phi[M]={0};
int oula3(int n){

    int cnt=0;
    for(int i=2;i<M;i++){
        if(vis[i]==0){
            prime[cnt++]=i;
            phi[i]=i-1;//i如果是素数,那么前面i-1个都与它互质。
        }
        for(int j=0;j<cnt&&prime[j]*i<M;j++){
           vis[i*prime[j]]=1;
           if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;//防止重复计算,线性的根本
           }
           else phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }
    return phi[n];
}
int main()
{
    int n;
    cin>>n;
    cout<<oula1(n)<<endl;
    //cout<<oula2(n)<<endl;
    //cout<<oula3(n)<<endl;
    return 0;
}
/**
欧拉函数性质:
1.1.对于素数p, φ(p)=p-1,对于对两个素数p,q  φ(pq)=pq-1
2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn.
   φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn).
3.除了N=2,φ(N)都是偶数.
4.设N为正整数,∑φ(d)=N (d|N).


oula2:
     它在O(Nlog(m))的时间内遍历了所有的数,

    φ(n)=n*(1-1/p1)(1-1/p2)....(1-1/pk),其中p1、p2…pk为n的所有素因子。
    比如:φ(12)=12*(1-1/2)(1-1/3)=4。
    利用这个就比较好求了,可以用类似求素数的筛法。
    先筛出N以内的所有素数,再以素数筛每个数的φ值。
    比如求10以内所有数的φ值:
    设一数组phi[11],赋初值phi[1]=1,phi[2]=2...phi[10]=10;
    然后从2开始循环,把2的倍数的φ值*(1-1/2),
    则phi[2]=2*1/2=1,phi[4]=4*1/2=2,phi[6]=6*1/2=3....;
    再是3,3的倍数的φ值*(1-1/3),则phi[3]=3*2/3=2,phi[6]=3*2/3=2,phi[9]=.....;
    再5,再7...因为对每个素数都进行如此操作,
    因此任何一个n都得到了φ(n)=n*(1-1/p1)(1-1/p2)....(1-1/pk)的运算
    以前求数的所有因子之和也是用的它。

oula3:
void PHI()  //即可以求出素数,还可以求出欧拉函数的值! 模板。
{
    int cnt=0;
    for(int i=2;i<M;i++){
    if(vis[i]==0){
        prime[cnt++]=i;
        phi[i]=i-1;     //i如果是素数,那么前面i-1个都与它互质。
    }
     for(int j=0;j<cnt&&prime[j]*i<M;j++){
       vis[i*prime[j]]=1;
       if(i%prime[j]==0){
            phi[i*prime[j]]=phi[i]*prime[j];
            break;//防止重复计算,线性的根本
       }
       else phi[i*prime[j]]=phi[i]*phi[prime[j]];
		}
    }
}
    在筛素数的同时求出所有数的欧拉函数呢.
     phi[i*prime[j]]=phi[i]*prime[j];
     //此时i%prime[j]==0说明prime[j]是i的一个素因子当然也是i*prime[j]的一个素因子,
     那么phi[i*prime[j]]=(i*prime[j])*(1-1/p1)*(1-1/p2)....*(1-1/prime[j])....
    又phi[i]=i*(1-1/p1)*(1-1/p2)....*(1-1/prime[j])....
    phi[i*prime[j]]=phi[i]*phi[prime[j]];//如前文的奇性性质证明
*/

阅读更多
个人分类: acmer
所属专栏: acmer菜鸟学习工具
上一篇【菜鸟er】常见问题_ 韩信点兵算法
下一篇【菜鸟er】常见问题_ 位运算
想对作者说点什么? 我来说一句

Fluent 菜鸟必读

2011年05月19日 714KB 下载

没有更多推荐了,返回首页

关闭
关闭