欧拉函数学习笔记
——摘自维基百科(链接)
欧拉函数,最初听起来很高深,可实际真的很简单。
φ(1)=1这是一个特殊情况。
(p代表质因数)
但怎么求呢?
法一:埃拉托斯提尼筛(线性筛法)
想法很古老且简单,实现也很容易
设a[i]为i的欧拉函数
就是从2开始往后把整个范围内的倍数筛掉(标记为合数)
然后依次寻找那些没有被筛的继续筛
最后剩下的进行如下操作:
a[j]=a[j]/i*(i-1)(同上图)
便完成了
时间复杂度:O(n log n)
代码:
#include<cstdio> #include<algorithm> using namespace std; int a[100015],n; int main() { a[1]=1; for(register int i=2;i<=100010;i++) { a[i]=i; } for(register int i=2;i<=100010;i++) { if(a[i]==i) { for(register int j=i;j<=100010;j+=i) { a[j]=a[j]/i*(i-1); } } }while(~scanf("%d",&n)) { printf("%d\n",a[n]); } return 0; }
法二:欧拉筛
这种方法提高了时间复杂度
设prime[j]表示现在做到了第j个素数
这是便要分两种情况讨论:
1.prime[j]是i的质因数
则:
a[prime[j]*i]=a[i]*prime[j]; break;/*这是最关键的一步,免得重复筛选其他质因数浪费时间*/
2.prime[j]不是i的质因数
则:
a[prime[j]*i]=a[i]*a[prime[j]];/*根据前文的公式可推*/
每个数被它最小的质因数筛之后再判断
时间复杂度:O(n)
代码:
#include<cstdio> #include<cstring> using namespace std; int a[100015],prime[100015],shu1,n; bool bz[100015]; int main() { a[1]=1; shu1=0; memset(bz,true,sizeof(bz)); for(register int i=2;i<=100010;i++) { if(bz[i]==true) { prime[++shu1]=i; a[i]=i-1; } for(register int j=1;j<=shu1&&prime[j]*i<=100010;j++) { bz[prime[j]*i]=false; if(i%prime[j]==0) { a[prime[j]*i]=a[i]*prime[j]; break; } else { a[prime[j]*i]=a[i]*a[prime[j]]; } } } while(~scanf("%d",&n)) { printf("%d\n",a[n]); } return 0; }
加油!