CSP初赛复习-18-数论-最大公约数-最小公倍数
CSP初赛复习-最大公约数-最小公倍数
常见符号
1 整除符号:x| y, x整除y
2 最大公约数:gcd(x,y),简写为(x,y)
3 最小公倍数:lcm(x,y),简写为[x,y]
4 整数集 Z
5 自然数集 N
6 实数集 R
7 属于符号: x∈N x在自然数范围内的数
因数 -约数
如果 d|a 且 d>=0 则称d是a的因数 ,因数也可以被称为约数
例如
2|8 ,则称2是8的因数,或者称2是8的约数
公约数
如果数p同时是两个数a,b的约数,我们就称p为a和b的公约数
即 p|a , p|b 则p是a和b的公约数
例如
2|4 ,2|6 则2是4和6的公约数
最大公约数
a和b的所有公约数中最大的那个数称为a和b的最大公约数
24的约数
1 2 3 4 6 8 12 24
18的约数
1 2 3 6 9 18
18和24的公约数
1 2 3 6
公约数最大的是6,所以6是18和24的最大公约数
倍数
一个整数能够被另一个整数整除,这个整数就是另一整数的倍数。如15能够被3或5整除,因此15是3的倍数,也是5的倍数。
即: 3|15 ,5|15 ,所以15是3的倍数 ,15也是5的倍数
公倍数
如果数p同时是两个数a和b的倍数,我们就称p为a和b的公倍数
6的倍数
6 12 18 24 30 36 42 48 54 ...
9的倍数
9 18 27 36 45 54 ...
最小公倍数
a和b的所有公倍数中最小的那个数称为a和b的最小公倍数
6和9的公倍数
18 36 54
最小的公倍数是18,所以18是6和9的最小公倍数
最大公约数/最小公倍数性质
性质1
若整数a,b都能整除m,则a,b的最小公倍数也能整除m
即 a|m , b|m 则 LCM(a,b)|m
例如
2|12 ,3|12 ,则LCM(2,3)=6|12
性质2
若d能整除整数a,b,则d能整除a,b的最大公约数
即 d|a, d|b ,则d|GCD(a,b)
例如
2|4 ,2|6 ,GCD(4,6)=2 ,则2|GCD(4,6) 即 2|2
性质3
如果b∈正整数,则0和b的最大公约数是b,1和b的最新公倍数是b
即
b∈N+ 则 GCD(0,b)=b , LCM(1,b)=b
例如
GCD(0,5)=5
LCM(1,5)=5
性质4
对于任意整数x,有GCD(a,b)=GCD(a,b+ax);
示例1
GCD(4,6)=2
GCD(4,6+2*4)=GCD(4,14)=2
示例2
GCD(6,9)=3
GCD(6,9+2*6)=GCD(6,21)=3
求最大公约数
1 枚举法
两个数的最大公约数一定小于或等于两数中较小的数,并且这两个数必定至少存在一个公因数 1
因此最大公约数存在范围再较小的数到1之间,可以将两个数的最大公约数的所有可能都列举出来
参考程序
#include <stdio.h>
int a,b,min;
int main(){
scanf("%d%d", &a, &b);
if (a > b)
min = b;
else
min = a;
for (int i = min; i > 0; i--){//从min 到 1 逐一枚举
// i是 a的约数 并且 i是b的约数 则是公约数
//公约数i 是从大到小枚举 找到第一个则是最大公约数
//如果没有其他公约数 一定有一个公约数满足 即为 1
if (a % i == 0 && b % i == 0){
printf("最大公约数为 %d", i);
break;
}
}
return 0;
}
/*
输入
4 6
输出
2
*/
时间复杂度
O(min(a,b))
2 更相减损法
更相减损法是出自《九章算术》的一种求最大公约数的算法
大致实现逻辑如下
若c是a和b的公约数(a>b), c 也是b和(a-b)的公约数,可以表示成 gcd(a,b) = gcd(b,a-b)
采用递归逐渐缩写法 当a和b相等时,此时的a为a和b的最大公约数
参考程序1 非递归
#include <stdio.h>
int a,b,min;
int main(){
scanf("%d%d", &a, &b);
while(a!=b){
if(a>b) a=a-b;
else b=b-a;
}
printf("最大公约数是 %d",a);
return 0;
}
/*
输入
4 6
输出
2
*/
参考程序2 递归
#include<bits/stdc++.h>
using namespace std;
int a,b;
int gcd(int a,int b){
if(a==b) return a;// a==b a或者就是最大公约数 退出
if(a<b){//保证a总是大 方便后面 程序gcd(b,a-b)统一规则
swap(a,b);
}
return gcd(b,a-b);//继续递归
}
int main(){
scanf("%d%d", &a, &b);
int c=gcd(a,b);
printf("最大公约数是 %d",c);
return 0;
}
/*
输入
4 6
输出
2
*/
时间复杂度
最坏时间复杂度 O(max(a,b))
3 辗转相除法 - 欧几里得算法
用一个数除以另一个数,如果余数不为 0,则用除数除以余数,一直反复,直到余数为 0 为止
把两个数看作被除数与除数的关系,则两个数的最大公约数就等于除数与余数的最大公约数
即
r=a%b
gcd(a,b) = gcd(b,r)
参考程序
#include<bits/stdc++.h>
using namespace std;
int a,b;
int gcd(int a,int b){
if(b==0) return a;
else{
return gcd(b,a%b);
}
}
int main(){
scanf("%d%d", &a, &b);
int c=gcd(a,b);
printf("最大公约数是 %d",c);
return 0;
}
/*
输入
4 6
输出
2
*/
时间复杂度
\(O(\log_2{(max(a,b))})\)
求最小公倍数
定理
两个数a和b的乘积会刚好等于它们的最大公约数和最小公倍数的乘积
即 a * b = (x,y) * [x,y]
例如
a=6 b=9
(6,9) = 3
[6,9] = 18
所以
6 * 9 =3 * 18
通常可以用来根据最大公约数求最小公倍数
因此 a和b的最小公倍数
LCM(a,b)=a * b /GCD(a,b)
为防止a * b数太大超出int或long long范围,可以稍加变形
LCM(a,b)=a /GCD(a,b) * b
求大公约数三种方法都可以用来求最小公倍数,如下程序以辗转相除法做示例
参考程序
#include<bits/stdc++.h>
using namespace std;
int a,b;
int gcd(int a,int b){
if(b==0) return a;
else{
return gcd(b,a%b);
}
}
int main(){
scanf("%d%d", &a, &b);
int c=gcd(a,b);
int d=a/c*b;
printf("最小公倍数是 %d",d);
return 0;
}
/*
输入
4 6
输出
12
*/
作者:newcode 更多资源请关注纽扣编程微信公众号
从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习