【基础数论】十分钟学会计算欧拉函数
2015-08-20 12:50
281 查看
欧拉函数
欢迎各位读者指出不足,谢谢~首先我们要知道欧拉函数是个什么东东?
废话不多说~欧拉函数就是指:对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) 。
欧拉函数的通式:φ(n)=n*(1-1/p1)*(1-1/p2)*(1-1/p3)*(1-1/p4)…..(1-1/pn),其中p1, p2……pn为n的所有质因数,n是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)。
对于上述的通式一定要牢记在心,因为这是计算欧拉函数最重要的一步。 切记切记~~~~
好,最简单的,我们根据通式即可得 最简单的代码:
int euler(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; }
晦涩难懂一:代码中的 ans-=ans/i; 这一步就是对应欧拉函数的通式~还是应该比较容易看懂的吧?
晦涩难懂二:while(n%i==0) n/=i; 这一个语句是为了保证完全消除我们刚才得到的那个i因子。确保我们下一个得到的i是n的素因子。
晦涩难懂三:if(n>1)ans-=ans/n; 这个语句是为了保证我们已经除完了n的所有的素因子,有可能还会出现一个我们未除的因子,如果结尾出现n>1 ,说明我们还剩一个素因子木有除。
看懂上述代码的就可以去练练手了~ 推荐题目:HDOJ 1787 题解:点击打开链接
但是我们一般做的题当然不会这么简单啊~~来点稍微难一点点的。。。
如果我们要求的数比较多,如果一个一个求那么很容易就超时,所以我们自然而然就想到——打表。
如果我们依照上述思想,来个最朴素的打表。
void euler() { p[1]=1; for(int i=2;i<=MAXN;i++){ int n=i; p[i]=i; for(int j=2;j*j<=n;j++){ if(n%j==0){ p[i]=p[i]/j*(j-1); while(n%j==0) n=n/j; } } if(n>1) p[i]=p[i]/n*(n-1); } for(int i=2;i<MAXN;i++) p[i]+=p[i-1]; }
这种打表方法并不是很理想。。。。
下面推荐 两种较快的打表方法:
ps:这种好像稍微快那么一点点~
void euler() { E[1]=1; for(int i=2;i<maxn;i++) E[i]=i; for(int i=2;i<maxn;i++){ if(E[i]==i) for(int j=i;j<maxn;j+=i){ E[j]=E[j]/i*(i-1); } } }
第二种:
void euler() { for(int i=2;i<maxn;i++){ if(!E[i]) for(int j=i;j<maxn;j+=i){ if(!E[j])E[j]=j; E[j]=E[j]/i*(i-1); } } }
上述打表方法的思想和最初的是差不多的。但是它进行了优化,所以比较快。
我们逐步分析一下:
首先,在这里我们枚举的是素因子。因为素因子比较少,如果枚举素因子的话肯定会大大优化复杂度?
那么,我们如何保证我们得到的就一定是个素因子呢?这就是我们if语句的作用,例如在第一种方法中,我们在第二个for 循环中就是把所有数,除以素因子。这样得到的复杂度一定比枚举每个数,然后找素因子(最开始那个打表法)这种打表要优化的多。
推荐题目:HDOJ 2824 题解:点击打开链接
在平时,我们做题,一般不会直接或者只是考察一个数的欧拉函数值。而是一些变形,或者是欧拉函数的一些性质。
在这我总结了几个欧拉函数常用的性质,希望读者多多补充。
欧拉函数性质(持续更新):
①N>1,不大于N且和N互素的所有正整数的和是 1/2*M*eular(N)。 推荐题目:HDOJ 3501 题解:点击打开链接
②若(N%a==0 && (N/a)%a==0) 则有:E(N)=E(N/a)*a;
③若(N%a==0 && (N/a)%a!=0) 则有:E(N)=E(N/a)*(a-1);
相关文章推荐
- Python的字符串操作和Unicode
- 黑马程序员——java基础语法
- ActiveMQ消息传送模型
- PAT《数据结构学习与实验指导》实验项目集 2-05. 求集合数据的均方差(15) C语言
- 继承关系类实例对象的非绑定关系方法调用
- 数学真头疼
- csv读入数据,用julia/matplotlib/pyplot 画矢量图导入word中
- android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件
- 本地拦截genymotion或者Android模拟器的网络请求
- innodb 悲观锁,乐观锁
- 组件的使用(三)AutoCompleteTextView的使用
- socket编程中对sigpipe信号的处理
- Android开源项目第五篇——优秀个人和团体篇
- ELF文件格式以及装载过程
- 使用live delegate on解决js后装html故障问题
- Jquery
- Android开源项目第三篇——优秀项目篇
- ClassLoader—流程观察程序执行类加载-verbose:class
- 剑指offer-第四章解决面试题思路之总结
- Android开源项目第二篇——工具库篇