一、如何求最大公因数?
1.更相减损法
两个正整数a和b(a>b),它们的最大公约数等于a-b的差值c和较小数b的最大公约数。
int gcd(int a,int b)
{
if(a==b)
return a;
if(a>b)
return gcd(a-b,b);
if(a<b)
return gcd(b-a,a);
}
2.辗转相除法
两个正整数a和b(a>b),它们的最大公约数等于a除以b的余数c和b之间的最大公约数。
int gcd(int a,int b)
{
if(b==0)
return a;
else
return gcd(b,a%b);
}
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
**规律**:
1~n的gcd为n/2 -->(好用)
二、欧拉定理
互质的正整数a和n,有a^(φ(n)) = 1 mod n;
三、费马小定理
因为,对于素数p,φ§ = p -1;
若正整数a与素数p互质,则有a^(p-1) = 1 mod p;
四、欧拉函数的公式
(1) p为素数,正整数 n = p^k
φ(n) = p^k - p^(k-1)
(2) p,q是两个互质的正整数,n = pq则:
φ(n) = φ(p) φ(q)
(3) 当b 是质数,a%b = 0,则:
φ(ab) = φ(a) b
(4) 对于任意n:
φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)
递推式求欧拉函数:
int euler(int n) //求φ(n)
{//递推式:质数p满足p|x,若p2|x,则φ(x)=φ(x/p)*p,若p2|x不成立则
φ(x)=φ(x/p)*(p-1)
int ret=1;
for(int i=2;i*i<=n;i++){ //只要考虑sqrt(n)以内的素数
if(n%i==0){//i若是合数则不可能满足此条件,因n里面已经不含小于i的素因子
n/=i,ret*=i-1; //最后总会剩一个i,n/i不整除i
while(n%i==0){
n/=i,ret*=i;
}
}
}
if(n>1) ret*=n-1;//到此所有<= sqrt(最初的n)的因子都已经去掉。如果
还剩一个因子,该因子一定 > sqrt(最初的n),则该因子只有一个
return ret;
}
五、扩展欧几里得算法
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。
int exgcd(int a, int b, int&x, int&y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int r = exgcd(b, a%b, y, x);
y = y - a/b*x;
return r;
}
六、gcd题目学习
1.题目B
题意:求所有数任意两数的最小公倍数,再求所有最小公倍数的gcd(最大公因数)。
求任意两数最小公倍数,就是求两数公共素数因子的次方较大值,而求gcd就是求所有较大值中,最小值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n;
ll a[N];
ll lcm(ll a,ll b)
{
return a*b/__gcd(a,b);
}
ll r[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=n;i>=1;i--)
r[i]=__gcd(a[i],r[i+1]);
ll res=0;
for(int i=1;i<=n;i++)
{
res=__gcd(res,lcm(a[i],r[i+1]));
}
cout<<res<<endl;
}
2.题目技巧
1、如果让你求其中的一种情况,这种题目一般都是可以有特殊解的,而且只要找的"某种规律“,就可以几行解决这个问题。
例子1:
题意:
给你一个x,求a,b使GCD(a,b)+LCM(a,b)=x成立。
最大公因数和最小公倍数,其中1和i的最大公因数是1,最小公倍数是i-1,并且满足上试成立。所以可以直接输出。