欧拉函数的一些模板+注释
来源:互联网 发布:淘宝网店如何起步 编辑:程序博客网 时间:2024/05/18 02:16
将要学习数论,选择一套题来拓展知识面。机缘巧合之下就理解了埃氏素数筛法,和线性筛法的相似之处,特记下模板以及理解。
简单说一下欧拉函数(来源百度百科):在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)。比如:φ(10)=4,那么与他互质的数有哪些呢? 1,3,7,9。
而求欧拉函数值有一个通式:φ(x)=x*(1-1/x1)(1-1/x2)…
而这些x1,x2等等都是x的质因数,什么是质因数呢?首先要先是质数(素数),其次也要是x的因子,比如x=10,那么x1=2,x2=5,代入得φ(10)=10*(1/2)*(4/5)=4。
但是呢,类似于素数,我们用的时候往往是比较很大很大的范围的数,所以既然素数都有素数筛法打表,那么就会有筛法欧拉函数。
类似于素数筛法,都是找因子的倍数关系的数,素数筛法原理就是2既然是素数,那么2的倍数就不再是素数,统统打死。。。而筛法欧拉函数的原理就根据那个通式来完成的,通式里面,要求x1,x2是质因子,而素数筛法则可以很好的吧所有素数过滤出来,那么每过滤一个素数,那么以它为质因子的数是不是都可以进行一下那个通式的运算?对,这就是原理。
附上代码:
//筛法欧拉函数<by kuangbin>int euler[1000000+10];void geteuler(){ mem(euler,0); euler[1]=1; for(int i=2;i<=1000000;i++) { if(!euler[i]) { for(int j=i;j<=1000000;j+=i) { if(!euler[j]) { euler[j]=j; } euler[j]=euler[j]/i*(i-1); } } }}
接着,若只是简单的计算一下单个或少量值得欧拉函数值,就不需要打表啦,所以这个时候,计算单个数的欧拉函数值就应运而出了。
LL euler(LL n){ LL 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;}
下面解释一下代码。。。看了几十分钟,也是没谁了。。。
首先,我们想一下,怎么去求一个数n的欧拉函数值,答案是求出n的所有质因子,然后套公式。但关键之处有两点,怎么筛选出素数,怎么利用公式求欧拉函数值。
这几行代码,虽然简单,但是却又好多东西。(一点一点解释)
最外层的 for循环和if(n%2)用于判断素数,(可以回忆下判断一个数是不是素数的模板的那一层for循环(for(int i=2;i<=sqrt(n);i++)),但是要记得,这里的i表示的质因子并不能代表全部,因为i(max)=sqrt(n),举个例子,6的话,i表示的质因子只能到2,3的话i循环不到。所以才有了n/=i的特判。
感觉读的人会迷迷糊糊,所以,继续解释, ans-=ans/i;这一行代码变化一下形式就是ans=ans(i-1)/i;似曾相识对吧,上文中有提到过,这就是通式的一部分。我看的时候,在想,既然都已经把所有质因子都代入通式了,为什么还要n去变化,去变小。因为有的一部分质因子在for循环里并没有加入到通式里,如果没加入,n就不会是1,if(n>1) ans-=ans/n;因为任何一个数都可以拆成质因子的乘积,但是,我就想了,难道不在for循环里的质因子只有一个吗?为什么只要一次加入通式就可以了?因为如果有多个质因子没有在for循环里加入通式的话,比如(当然这只是错误的例子)10,假如2,5没有加入通式,那么n的值是10(2*5),那么 ans-=ans/n这个式子分别代入2,5和直接代入10是不一样的,所以我就猜测是不是只剩一个质因子不在for循环里。
那么接着验证我的猜测,重点还是在一句话,所有大于1的正整数都可以拆成质因子的乘积,举个例子,10,sqrt(10)近似为3,所以,剩5不在for循环,若是有质因子不在for循环里,只可能是最大的一个。
还有一点疑惑哦,是为什么n每次除以i,依旧举个例子,n=8,当循环过i==2时,n变成了4,那么若是n能被除成1,说明后面不在有质因子。你觉得呢。
然后呢,就是最后一种代码模板了。。。
线性筛法(同时得到欧拉函数值和素数表)
bool check[1000000+10];int phi[1000000+10];int prime[1000000+10];int tot;//素数的个数void phi_and_prime(){ mem(check,0); phi[1]=1; tot=0; for(int i=2; i<=1000000; i++) { if(!check[i]) { prime[tot++]=i; phi[i]=i-1;//若i是素数,那么φ(i)=i-1。(定理) } for(int j=0; j<tot; j++) { if(i*prime[j]>1000000) break;//只求1000000以内的素数 check[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]*(prime[j]-1); } } }}
留下一个自己钻研去吧。。。。0.0
- 欧拉函数的一些模板+注释
- 欧拉函数--模板
- 欧拉函数模板
- 欧拉函数模板
- 欧拉函数模板
- 欧拉函数【模板】
- 欧拉函数 模板
- 欧拉函数模板
- 【欧拉函数模板】
- 欧拉函数模板
- 欧拉函数模板
- 【模板】欧拉函数
- 欧拉函数模板
- 欧拉函数模板
- 欧拉函数模板
- 欧拉函数模板
- 欧拉函数模板
- 欧拉函数模板
- 腾讯地图定位demo
- 匿名函数
- DOM4J操作XML
- ROS(Robot Operating System)常用环境变量介绍
- vim编辑代码自动补全设置
- 欧拉函数的一些模板+注释
- Eclipse中SVN修改的*星号没了,解决方法
- 第八节:Array的遍历-转换以及-常规用法
- 来谈谈WebAssembly是个啥?为何说它会影响每一个Web开发者?
- 数据库泵(expdp/impdp)导入导出流程
- .NET插件技术-应用程序热升级
- spring 框架说明文档学习记录(3.3)
- Android 使用<layer-list>实现微信聊天输入框
- 求解强联通分量 tarjan算法