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
*/
posted @ 2023-07-28 21:24  new-code  阅读(127)  评论(0)    收藏  举报