最大公约数与最小公倍数

基础知识

最大公约数:

最大公约数就是两个数的最大公共因子

x = abc , y = bcdef  (a ~ f 均为质因子)

gcd ( x , y ) = bc

计算方法:

1.质因数分解法,如上举例所示

2.欧几里得算法(辗转相除法)

算法原理:gcd(a,b) = gcd( b ,  a % b)  

三目运算符(较快)

 

int gcd(int a , int b ){
    return !b ? a : gcd(b, a % b);
}

 

 

位运算(超快)( a , b不能为0)

int gcd(int a , int b){
    while(b ^= a ^= b ^= a %= b);
    return a;
}

 分析:

b^=a^=b^=a%=b可以写为  a%=b ,  b ^= a , a ^= b , b ^= a ; 

后面三句相当于swap(a , b)

于是就变为a %= b , swap(a , b)

这就是最基本的辗转相除法

https://blog.csdn.net/Ljnoit/article/details/104604806

最小公倍数

最小公倍数是两个数的所有质因子的积

x = abc , y = bcdef  (均为质因子)

则  lcm(x , y ) = abcdef

(分式加减时都要将分母化为最小公倍数)

计算方法:

lcm( a , b ) = a * b / gcd( a , b )

 

常用性质

  • gcd(b∗ lcm(a,ba * b
  • gcd(a , b) = m , 则 gcd( a/m , b/m ) = 1
  • 同理,若lcm( a , b ) = k , 则 gcd( k/b , k/a ) = 1

 

 

 

例题

1.最大公约数与最小公倍数问题

(https://www.luogu.com.cn/problem/P1029)

 

 

解题思路:

gcd(P,Q)  = x0, lcm(P,Q) = y0   可推出  x0 <= P , Q <= y0 

确定了范围,然后 双层遍历,看是否满足条件就好  这样会超时,所以要将算法优化到O(N)

将Q用P表示就好,利用性质   gcd(P , Q∗ lcm(P , Q= P * Q

Q = x0 * y0 / P;

注意:

遍历从x0 ~ sqrt(x0*y0)  是因为结果 P * Q  和 结果 Q * P ,只用算一次,之后再乘2就好,但是如果x0 == y0 ,只用 加1次

代码:

#include<bits/stdc++.h>
using namespace std;
int gcd(int a , int b){
    return !b ? a : gcd(b, a%b);
}
int main(){
    int x0,y0;
    cin >> x0 >> y0;
    int t = x0 * y0;
    int ans = 0;
    for(int i = x0 ; i < (int)sqrt(t) ; i++){
        if(t % i == 0 && gcd(t/i , i) == x0){
            ans++;
        }
    }
    if(t % (int)sqrt(t) == 0 && gcd(t / (int)sqrt(t),(int)sqrt(t)) == x0)
        cout << ans*2 + 1 << endl; 
    else 
        cout << ans*2 << endl;
    return 0;
}

 

 

 

2.P1072 Hankson 的趣味题

https://www.luogu.com.cn/problem/P1072

比较好的题解:https://www.luogu.com.cn/blog/zzlzk/solution-p1072

题意:

输入四个数,a0,a1,b0,b1 求x使得条件:

1. x 和 a0 的最大公约数是 a1

2. x 和 b0 的最小公倍数是 b1

问x的个数

 

解题思路: 

由题意能得到的信息

  • x一定时最小公倍数 b1 的因子,一定是最大公约数 a1 的倍数,a1 <= x <= b1

我们要做的就是从1到sqrt(b1)遍历其因子,且该因子能 整除 a1,

同时它还要满足题中的两个条件,如果都满足 ans++

注意:相等因子只加一次

*** 这里有个问题,如果按照题中条件判断有可能爆int导致判断不准,所以我们要对条件进行处理

用到了性质

  • 若gcd(a , b) = m , 则 gcd( a/m , b/m ) = 1
  • 同理,若lcm( a , b ) = k , 则 gcd( k/b , k/a ) = 1
#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
    if(b > a)swap(a,b);
    return !b ? a : gcd(b , a % b);
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int a0,a1,b0,b1;
        scanf("%d %d %d %d",&a0,&a1,&b0,&b1);
        int ans = 0;
        for(int i = 1 ; i * i <= b1; i++){
            if(b1 % i != 0)continue;//不是因子,继续 
            if((i % a1 == 0) && gcd( i , a0 ) == a1 && gcd( b1/b0 , b1/i ) == 1){
                ans++;
            }
            int j = b1 / i;
            if(j == i)continue;//相等因子只判断一次 
            if((j % a1 == 0) && gcd( j , a0 ) == a1 && gcd( b1/b0 , b1/j ) == 1){
                ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

如果还是不理解可以看上面大佬的博客

 

 

3.P4057 [Code+#1]晨跑

https://www.luogu.com.cn/problem/P4057

 

这个题比较简单,就是给出三个人每隔几天运动 的天数a,b,c,问三个人下次碰到是什么时候

就是三人的最小公倍数

#include<bits/stdc++.h>
using namespace std;
long long gcd(long long a , long long b){
    if(!b)return a;
    else return gcd(b,a%b);
}
int main(){
    long long a,b,c;
    scanf("%lld %lld %lld",&a,&b,&c);
    long long ans = a / gcd(a,b) * b;
    ans = ans / gcd(ans,c) * c;
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2020-06-21 16:50  w_w_t  阅读(693)  评论(0编辑  收藏  举报