欧几里得GCD:
GCD算法是使用辗转相除法求最大公因数的算法,简单而言就是gcd(a,b) = gcd(b,a mod b)
递归写法:
int Gcd(int a, int b)
{
if(b == 0)
return a;
return Gcd(b, a % b);
}
迭代写法:
int Gcd(int a, int b)
{
while(b != 0)
{
int r = b;
b = a % b;
a = r;
}
return a;
}
欧拉函数:
欧拉函数Euler(n):表示不大于n且与n互质的正整数的个数。
由唯一分解定理,n=p1^k1*p2^k2*...*pn^km,pi均为质数,ki是其幂次。
由此可推出欧拉函数的求法:Euler(n)=n/p1*(p1-1)/p2*(p2-1)/.../pn*(pn-1)
上面的公式该怎么理解呢?
让我们看看GPT怎么说
也就是说最终的目的就是去除掉所有质因数。上式中的1/pi*(pi-1) == (1- 1/pi),本质一样。
代码:
ull Euler(ull n)//求n的欧拉函数(固定模板)
{
ull phi=n;
for(int i=2;i*i<=n;i++)//枚举n的质因数
{
if(n%i)continue;
while(n%i==0)//i是质因数
{
n=n/i;//n不断除以i直至i不再是n的质因数
}
phi=phi/i*(i-1);//递推欧拉函数,Euler(n)=n/pi*(pi-1)
}
//最后可能还剩下一个大于n的因子,如12=2*2*3,最后将剩下3,补充上
if(n>1)phi=phi/n*(n-1);
return phi;
}
我们简单解释下这个代码。根据上面的结论,如果 p 为素数,n 是 p 的正整数次方,那么Euler(n) = n * (1 - 1/p)。所以phi=phi/i*(i-1);就是在求每个质因子带来的互质数的个数。而while循环则是在不断的改变n,因为我们每次迭代一个因子的同时,我们在计算完phi后要消除这个质因子在n中的影响,所以我们通过while循环不断除以这个因子。
为什么是 i * i <= n呢?这是因为 12 = 2 * 6,有了2就不需要另一部分了。
最后如有遗漏的情况也加上。